Files
gen1recomp/tests/emerald_audio_test.lua
T
bryanthaboi 690f0cd9a1 TOUCHDOWN
2026-09-27 16:07:31 -04:00

103 lines
4.2 KiB
Lua

package.path = "./?.lua;./?/init.lua;" .. package.path
local T = require("tests.harness")
local check, eq = T.check, T.eq
local ROM_PATH = os.getenv("POKEPORT_EMERALD_ROM") or "../pokeemerald/pokeemerald.gba"
local f = io.open(ROM_PATH, "rb")
if not f then
print("emerald_audio_test: skipped (no ROM at " .. ROM_PATH .. ")")
os.exit(0)
end
local rom = f:read("*a")
f:close()
local GameVersion = require("src.core.GameVersion")
GameVersion.set("emerald")
local Versions = require("src.import.gba.versions")
Versions.select("emerald")
local Constants = require("src.core.game3.constants")
local S = require("src.import.gba.syms").of("emerald")
local E = require("src.import.gba.extract_audio")
local C = Constants.of("emerald")
local function u16(off) local a, b = rom:byte(off + 1, off + 2) return a + b * 256 end
local files = {}
local cache = { write = function(_, p, b) files[p] = b; return true end }
local ok, idx = E.run({ data = rom }, cache, { sha1 = "f3ae088181bf583e55daf962a92bb46f4f1d07b7", cacheRoot = "g" })
check(ok, "extract ran")
eq(idx.songCount, 610, "610 songs")
eq(idx.songTable, S.off("gSongTable"), "song table at gSongTable")
local missing, bins = 0, 0
for id = 0, 609 do
if idx.songs[id].missing then missing = missing + 1 end
if files[("g/audio/songs/%d.bin"):format(id)] then bins = bins + 1 end
end
eq(missing, 0, "every song header resolves")
eq(bins, 610, "one bin per song")
eq(idx.songs[C.songs.byName.MUS_TITLE].kind, "bgm", "MUS_TITLE is a BGM")
eq(idx.songs[C.songs.byName.PH_NURSE_SOLO].player, 2, "phoneme SEs ride SE2")
local EXPECT = {
{ 367, 80 }, { 370, 160 }, { 371, 220 }, { 372, 220 }, { 368, 160 }, { 369, 340 },
{ 378, 180 }, { 387, 120 }, { 388, 710 }, { 389, 250 }, { 390, 150 }, { 391, 160 },
{ 550, 450 }, { 530, 170 }, { 529, 196 }, { 459, 313 }, { 466, 318 }, { 460, 135 },
}
local nff = 0
for _ in pairs(idx.fanfares) do nff = nff + 1 end
eq(nff, #EXPECT, "18 fanfares")
for _, row in ipairs(EXPECT) do
local e = idx.fanfares[row[1]]
eq(e and e.frames, row[2], "fanfare " .. row[1] .. " frames")
eq(idx.songs[row[1]].kind, "fanfare", "song " .. row[1] .. " is a fanfare")
end
eq(idx.fanfares[C.songs.byName.MUS_OBTAIN_ITEM].name, "MUS_OBTAIN_ITEM", "fanfare named from constants")
local ncry, nrev, withSample = 0, 0, 0
for i = 0, 387 do
if idx.cries[i] then ncry = ncry + 1 end
if idx.criesReverse[i] then nrev = nrev + 1 end
if idx.cries[i] and idx.cries[i].sampleId then withSample = withSample + 1 end
end
eq(ncry, 388, "388 cries")
eq(nrev, 388, "388 reverse cries")
eq(withSample, 388, "every cry has a sample")
eq(idx.cryTableReverse, S.off("gCryTable_Reverse"), "reverse table offset")
check(files["g/audio/crytable_reverse.bin"] and #files["g/audio/crytable_reverse.bin"] == 388 * 12, "reverse table dump")
local sp = C.species.byName
local base = S.off("gSpeciesIdToCryId")
local bad = 0
for species = 1, sp.NUM_SPECIES - 1 do
local s, want = species - 1
if s <= sp.SPECIES_CELEBI - 1 then want = s
elseif s < sp.SPECIES_TREECKO - 1 then want = sp.SPECIES_UNOWN - 1
else want = u16(base + (s - (sp.SPECIES_TREECKO - 1)) * 2) end
if idx.cryIds[species] ~= want then bad = bad + 1 end
end
eq(bad, 0, "cryIds follow SpeciesToCryId over gSpeciesIdToCryId")
eq(idx.cryIds[sp.SPECIES_TREECKO], 273, "Treecko cry id")
eq(idx.cryIds[sp.SPECIES_LOTAD], 283, "Lotad cry id")
local nmap = 0
for _ in pairs(idx.mapSongs) do nmap = nmap + 1 end
eq(nmap, 496, "496 maps with music (22 MUS_NONE)")
local MapCatalog = require("src.import.gba.map_catalog")
local function mapId(name)
local row = C.map_groups.byName[name]
return MapCatalog.mapIdFor(row.group, row.num) or MapCatalog.pretToEngine(row.name)
end
eq(idx.mapSongs[mapId("MAP_ROUTE118")], C.songs.byName.MUS_ROUTE118, "MUS_ROUTE118 sentinel passes through")
eq(idx.mapSongs[mapId("MAP_LITTLEROOT_TOWN")], C.songs.byName.MUS_LITTLEROOT, "Littleroot music")
eq(idx.mapSongs[mapId("MAP_INSIDE_OF_TRUCK")], nil, "MUS_NONE maps are skipped")
eq(idx.roles.title, C.songs.byName.MUS_TITLE, "title role")
eq(idx.roles.battleWild, C.songs.byName.MUS_VS_WILD, "wild battle role")
eq(idx.roles.heal, C.songs.byName.MUS_HEAL, "heal role")
check(files["g/audio/meta.json"]:find('"song_count":610', 1, true) ~= nil, "meta.json song count")
T.finish("emerald_audio_test")