5 Cookbook Audio
bryanthaboi edited this page 2026-10-20 17:01:40 -04:00

Cookbook: audio

Start by reusing a song (R06) or playing your own file (R07/R43). ChipAsm is a separate, advanced route.

Setup: a working mod from Getting Started. Examples target Red/local single-player unless a recipe explicitly says otherwise. Use Modding Basics for syntax and Glossary for unfamiliar terms. Save and restart after content edits. A validation pass and an in-game checkpoint are different checks.

Where code goes: insert Lua fragments inside your existing return function(mod) ... end in main.lua. A complete-file label or named other file overrides that default. Do not paste a second entry function inside the first. Read the recipe's requirements before copying its code. For output, use Read log output; for IDs, use Find internal IDs.

Audio definition formats and the full workflow: Guide: Audio Authoring; worked path: Tutorial 09.

R06 - Retarget a map's music

First change. Before you paste: A working mod. This reuses an imported song, so no new audio file is needed. Enter Pallet Town after restarting and listen.

Complete walkthrough / required concept.

Insert in main.lua inside the entry function (unless a filename is shown).

mod.content.map_songs:override("PALLET_TOWN", "Music_Routes1")

Checkpoint: Pallet Town plays the Route 1 theme. map_songs maps map id to a music id; a new song registered through music slots in the same way.

Gen 2 / Gen 3: Gold keeps the shared map_songs target. On Gen 3 a map_songs row must name a music id your mod registers (a native MUS_* name is an unresolved reference), keyed by that game's map id, for example mod.content.map_songs:register("FR_PALLET_TOWN", "Music_ModChip") with R26's song.

R07 - Replace one SFX with a file

Basic Lua. Before you paste: Put your original sound at assets/save.ogg inside the mod. SFX means sound effect. Test by saving after the file loads.

Complete walkthrough / required concept.

Insert in main.lua inside the entry function (unless a filename is shown).

mod.content.sfx:override("Save", { file = mod.assets:path("assets/save.ogg") })

Checkpoint: saving plays your sound; other sound effects keep their original sound. This replacement applies only to the sound named Save. A def that fails to load is skipped with a mod-attributed log line when its cue fires.

Gen 3: key the row by the native sound name and register it, since there is no vanilla row to override: mod.content.sfx:register("SE_SAVE", { file = ... }). The Gen 3 audio engine plays it in place of the cart sound (src/core/game3/mod_audio.lua).

R26 - Author a chiptune (ChipAsm)

Advanced audio. Before you paste: This needs the supported ChipAsm module and imported base audio. It builds a chip program, not an audio file; test Pallet Town after loading it.

Complete walkthrough / required concept.

Insert in main.lua inside the entry function (unless a filename is shown).

local ChipAsm = require("src.audio.ChipAsm")

mod.content.music:register("Music_ModChip", ChipAsm.song({
  tempo = 140,
  channels = {
    { program = {
        { label = "top" },
        { notetype = { speed = 12, volume = 15, fade = 2 } },
        { octave = 4 },
        { note = "C", len = 4 }, { note = "E", len = 4 },
        { note = "G", len = 4 },
        { loop = { count = 0, to = "top" } },
    } },
  },
}))
mod.content.map_songs:override("PALLET_TOWN", "Music_ModChip")

Checkpoint: an authentic GB channel program plays with no audio file in the mod. src.audio.ChipAsm is a supported require; the event vocabulary is in Audio Authoring.

Gen 3: chip rows play on every Gen 3 game; point a Gen 3 map at the song with map_songs:register and that game's map id (see R06).

R43 - CD-quality map soundtrack (file-backed)

Basic Lua + audio. Before you paste: Supply both assets/pallet_intro.ogg and assets/pallet_loop.ogg in the mod. The first is an intro; the second is the repeating section.

Complete walkthrough / required concept.

MSU protocol is not implemented; streamed { file, loopFile } songs are the supported path for CD-quality replacements:

Insert in main.lua inside the entry function (unless a filename is shown).

mod.content.music:override("Music_PalletTown", {
  file = mod.assets:path("assets/pallet_intro.ogg"),
  loopFile = mod.assets:path("assets/pallet_loop.ogg"),
})

Checkpoint: Pallet Town plays your OGG; other maps stay chip. Pair with music.select if you need contextual swaps.

Gen 3: music:register("MUS_PALLET", { file = ..., loopFile = ... }) replaces FireRed's and LeafGreen's Pallet Town song by its native name (Hoenn songs have their own MUS_* names). music.select only sees mod songs on Gen 3; the cart's own songs never reach it.

R44 - Distance / indoor music volume

Hooks. Before you paste: Enter a Pokemon Center. This example halves its music volume; a gradual distance ramp would require your own position-based calculation.

Complete walkthrough / required concept.

Insert in main.lua inside the entry function (unless a filename is shown).

mod.hooks:wrap("music.volume", function(next, vol, ctx)
  vol = next(vol, ctx)
  if ctx.mapId and ctx.mapId:find("POKECENTER") then
    return vol * 0.5  -- muffled indoors
  end
  return vol
end)

Checkpoint: centers are quieter; the hook re-runs every frame while wrapped so tile-distance ramps work too (ctx.x / ctx.y).

Gen 3: only a mod song (a music row playing in place of a cart song) reaches music.volume; the cart's own songs are never scaled by it.

R55 - Give a species or a trainer its own battle theme

Basic Lua + audio. Before you paste: Provide assets/legend.ogg. The species example applies to a wild Mewtwo; the trainer example applies to Giovanni's trainer class.

Complete walkthrough / required concept.

Battle music normally comes from the kind alone (wild / trainer / gym / final). Two record fields override it for one opponent, both taking a music id, so a legendary can fight to its own track:

Insert in main.lua inside the entry function (unless a filename is shown).

mod.content.music:register("Music_LegendTheme",
  { file = mod.assets:path("assets/legend.ogg") })

-- wild battles with this species
mod.content.pokemon:patch("MEWTWO", { battleTheme = "Music_LegendTheme" })

-- every battle this trainer class fights
mod.content.trainers:patch("OPP_GIOVANNI", { battleTheme = "Music_LegendTheme" })

The species theme applies to wild battles only, so a trainer whose lead happens to be that species still fights to the trainer's own theme; trainers.battleTheme wins wherever both could apply. The victory jingle stays kind-based either way.

On Gold the same two fields work, spelled the same way; the trainer one lives on the trainer class record:

Outline / alternative: read the requirements above; this is not a complete mod.

mod.content.trainers:patch("FALKNER", { battleTheme = "Music_LegendTheme" })

Do not confuse it with encounterMusic, which is Gold's own key for the short jingle that plays while the trainer walks up (data/trainers/encounter_music.asm); the battle theme replaces it a moment later. Both can be set, and they do not collide.

Checkpoint: the wild encounter and that trainer's fight play your track; every other battle keeps the vanilla kind default.

Gen 3: no Gen 3 battle reads battleTheme; an api 3 mod gets unknown field battleTheme there.