Merge remote-tracking branch 'pret/master' into pret-merge

Converts all the expansion audio samples to use .wav
Adds the migration script bin_to_wav.py

 Conflicts:
	Makefile
	make_tools.mk
	sound/direct_sound_samples/cries/abra.aif
	sound/direct_sound_samples/cries/absol.aif
	sound/direct_sound_samples/cries/aerodactyl.aif
	sound/direct_sound_samples/cries/aggron.aif
	sound/direct_sound_samples/cries/aipom.aif
	sound/direct_sound_samples/cries/alakazam.aif
	sound/direct_sound_samples/cries/altaria.aif
	sound/direct_sound_samples/cries/ampharos.aif
	sound/direct_sound_samples/cries/anorith.aif
	sound/direct_sound_samples/cries/arbok.aif
	sound/direct_sound_samples/cries/arcanine.aif
	sound/direct_sound_samples/cries/ariados.aif
	sound/direct_sound_samples/cries/armaldo.aif
	sound/direct_sound_samples/cries/aron.aif
	sound/direct_sound_samples/cries/articuno.aif
	sound/direct_sound_samples/cries/azumarill.aif
	sound/direct_sound_samples/cries/azurill.aif
	sound/direct_sound_samples/cries/bagon.aif
	sound/direct_sound_samples/cries/baltoy.aif
	sound/direct_sound_samples/cries/banette.aif
	sound/direct_sound_samples/cries/barboach.aif
	sound/direct_sound_samples/cries/bayleef.aif
	sound/direct_sound_samples/cries/beautifly.aif
	sound/direct_sound_samples/cries/beedrill.aif
	sound/direct_sound_samples/cries/beldum.aif
	sound/direct_sound_samples/cries/bellossom.aif
	sound/direct_sound_samples/cries/bellsprout.aif
	sound/direct_sound_samples/cries/blastoise.aif
	sound/direct_sound_samples/cries/blaziken.aif
	sound/direct_sound_samples/cries/blissey.aif
	sound/direct_sound_samples/cries/breloom.aif
	sound/direct_sound_samples/cries/bulbasaur.aif
	sound/direct_sound_samples/cries/butterfree.aif
	sound/direct_sound_samples/cries/cacnea.aif
	sound/direct_sound_samples/cries/cacturne.aif
	sound/direct_sound_samples/cries/camerupt.aif
	sound/direct_sound_samples/cries/carvanha.aif
	sound/direct_sound_samples/cries/cascoon.aif
	sound/direct_sound_samples/cries/castform.aif
	sound/direct_sound_samples/cries/caterpie.aif
	sound/direct_sound_samples/cries/celebi.aif
	sound/direct_sound_samples/cries/chansey.aif
	sound/direct_sound_samples/cries/charizard.aif
	sound/direct_sound_samples/cries/charmander.aif
	sound/direct_sound_samples/cries/charmeleon.aif
	sound/direct_sound_samples/cries/chikorita.aif
	sound/direct_sound_samples/cries/chimecho.aif
	sound/direct_sound_samples/cries/chinchou.aif
	sound/direct_sound_samples/cries/clamperl.aif
	sound/direct_sound_samples/cries/claydol.aif
	sound/direct_sound_samples/cries/clefable.aif
	sound/direct_sound_samples/cries/clefairy.aif
	sound/direct_sound_samples/cries/cleffa.aif
	sound/direct_sound_samples/cries/cloyster.aif
	sound/direct_sound_samples/cries/combusken.aif
	sound/direct_sound_samples/cries/corphish.aif
	sound/direct_sound_samples/cries/corsola.aif
	sound/direct_sound_samples/cries/cradily.aif
	sound/direct_sound_samples/cries/crawdaunt.aif
	sound/direct_sound_samples/cries/crobat.aif
	sound/direct_sound_samples/cries/croconaw.aif
	sound/direct_sound_samples/cries/cry_unused_265.aif
	sound/direct_sound_samples/cries/cry_unused_268.aif
	sound/direct_sound_samples/cries/cubone.aif
	sound/direct_sound_samples/cries/cyndaquil.aif
	sound/direct_sound_samples/cries/delcatty.aif
	sound/direct_sound_samples/cries/delibird.aif
	sound/direct_sound_samples/cries/deoxys.aif
	sound/direct_sound_samples/cries/dewgong.aif
	sound/direct_sound_samples/cries/diglett.aif
	sound/direct_sound_samples/cries/ditto.aif
	sound/direct_sound_samples/cries/dodrio.aif
	sound/direct_sound_samples/cries/doduo.aif
	sound/direct_sound_samples/cries/donphan.aif
	sound/direct_sound_samples/cries/dragonair.aif
	sound/direct_sound_samples/cries/dragonite.aif
	sound/direct_sound_samples/cries/dratini.aif
	sound/direct_sound_samples/cries/drowzee.aif
	sound/direct_sound_samples/cries/dugtrio.aif
	sound/direct_sound_samples/cries/dunsparce.aif
	sound/direct_sound_samples/cries/dusclops.aif
	sound/direct_sound_samples/cries/duskull.aif
	sound/direct_sound_samples/cries/dustox.aif
	sound/direct_sound_samples/cries/eevee.aif
	sound/direct_sound_samples/cries/ekans.aif
	sound/direct_sound_samples/cries/electabuzz.aif
	sound/direct_sound_samples/cries/electrike.aif
	sound/direct_sound_samples/cries/electrode.aif
	sound/direct_sound_samples/cries/elekid.aif
	sound/direct_sound_samples/cries/entei.aif
	sound/direct_sound_samples/cries/espeon.aif
	sound/direct_sound_samples/cries/exeggcute.aif
	sound/direct_sound_samples/cries/exeggutor.aif
	sound/direct_sound_samples/cries/exploud.aif
	sound/direct_sound_samples/cries/farfetchd.aif
	sound/direct_sound_samples/cries/fearow.aif
	sound/direct_sound_samples/cries/feebas.aif
	sound/direct_sound_samples/cries/feraligatr.aif
	sound/direct_sound_samples/cries/flaaffy.aif
	sound/direct_sound_samples/cries/flareon.aif
	sound/direct_sound_samples/cries/flygon.aif
	sound/direct_sound_samples/cries/forretress.aif
	sound/direct_sound_samples/cries/furret.aif
	sound/direct_sound_samples/cries/gardevoir.aif
	sound/direct_sound_samples/cries/gastly.aif
	sound/direct_sound_samples/cries/gengar.aif
	sound/direct_sound_samples/cries/geodude.aif
	sound/direct_sound_samples/cries/girafarig.aif
	sound/direct_sound_samples/cries/glalie.aif
	sound/direct_sound_samples/cries/gligar.aif
	sound/direct_sound_samples/cries/gloom.aif
	sound/direct_sound_samples/cries/golbat.aif
	sound/direct_sound_samples/cries/goldeen.aif
	sound/direct_sound_samples/cries/golduck.aif
	sound/direct_sound_samples/cries/golem.aif
	sound/direct_sound_samples/cries/gorebyss.aif
	sound/direct_sound_samples/cries/granbull.aif
	sound/direct_sound_samples/cries/graveler.aif
	sound/direct_sound_samples/cries/grimer.aif
	sound/direct_sound_samples/cries/groudon.aif
	sound/direct_sound_samples/cries/grovyle.aif
	sound/direct_sound_samples/cries/growlithe.aif
	sound/direct_sound_samples/cries/grumpig.aif
	sound/direct_sound_samples/cries/gulpin.aif
	sound/direct_sound_samples/cries/gyarados.aif
	sound/direct_sound_samples/cries/hariyama.aif
	sound/direct_sound_samples/cries/haunter.aif
	sound/direct_sound_samples/cries/heracross.aif
	sound/direct_sound_samples/cries/hitmonchan.aif
	sound/direct_sound_samples/cries/hitmonlee.aif
	sound/direct_sound_samples/cries/hitmontop.aif
	sound/direct_sound_samples/cries/ho_oh.aif
	sound/direct_sound_samples/cries/hoothoot.aif
	sound/direct_sound_samples/cries/hoppip.aif
	sound/direct_sound_samples/cries/horsea.aif
	sound/direct_sound_samples/cries/houndoom.aif
	sound/direct_sound_samples/cries/houndour.aif
	sound/direct_sound_samples/cries/huntail.aif
	sound/direct_sound_samples/cries/hypno.aif
	sound/direct_sound_samples/cries/igglybuff.aif
	sound/direct_sound_samples/cries/illumise.aif
	sound/direct_sound_samples/cries/ivysaur.aif
	sound/direct_sound_samples/cries/jigglypuff.aif
	sound/direct_sound_samples/cries/jirachi.aif
	sound/direct_sound_samples/cries/jolteon.aif
	sound/direct_sound_samples/cries/jumpluff.aif
	sound/direct_sound_samples/cries/jynx.aif
	sound/direct_sound_samples/cries/kabuto.aif
	sound/direct_sound_samples/cries/kabutops.aif
	sound/direct_sound_samples/cries/kadabra.aif
	sound/direct_sound_samples/cries/kakuna.aif
	sound/direct_sound_samples/cries/kangaskhan.aif
	sound/direct_sound_samples/cries/kecleon.aif
	sound/direct_sound_samples/cries/kingdra.aif
	sound/direct_sound_samples/cries/kingler.aif
	sound/direct_sound_samples/cries/kirlia.aif
	sound/direct_sound_samples/cries/koffing.aif
	sound/direct_sound_samples/cries/krabby.aif
	sound/direct_sound_samples/cries/kyogre.aif
	sound/direct_sound_samples/cries/lairon.aif
	sound/direct_sound_samples/cries/lanturn.aif
	sound/direct_sound_samples/cries/lapras.aif
	sound/direct_sound_samples/cries/larvitar.aif
	sound/direct_sound_samples/cries/latias.aif
	sound/direct_sound_samples/cries/latios.aif
	sound/direct_sound_samples/cries/ledian.aif
	sound/direct_sound_samples/cries/ledyba.aif
	sound/direct_sound_samples/cries/lickitung.aif
	sound/direct_sound_samples/cries/lileep.aif
	sound/direct_sound_samples/cries/linoone.aif
	sound/direct_sound_samples/cries/lombre.aif
	sound/direct_sound_samples/cries/lotad.aif
	sound/direct_sound_samples/cries/loudred.aif
	sound/direct_sound_samples/cries/ludicolo.aif
	sound/direct_sound_samples/cries/lugia.aif
	sound/direct_sound_samples/cries/lunatone.aif
	sound/direct_sound_samples/cries/luvdisc.aif
	sound/direct_sound_samples/cries/machamp.aif
	sound/direct_sound_samples/cries/machoke.aif
	sound/direct_sound_samples/cries/machop.aif
	sound/direct_sound_samples/cries/magby.aif
	sound/direct_sound_samples/cries/magcargo.aif
	sound/direct_sound_samples/cries/magikarp.aif
	sound/direct_sound_samples/cries/magmar.aif
	sound/direct_sound_samples/cries/magnemite.aif
	sound/direct_sound_samples/cries/magneton.aif
	sound/direct_sound_samples/cries/makuhita.aif
	sound/direct_sound_samples/cries/manectric.aif
	sound/direct_sound_samples/cries/mankey.aif
	sound/direct_sound_samples/cries/mantine.aif
	sound/direct_sound_samples/cries/mareep.aif
	sound/direct_sound_samples/cries/marill.aif
	sound/direct_sound_samples/cries/marowak.aif
	sound/direct_sound_samples/cries/marshtomp.aif
	sound/direct_sound_samples/cries/masquerain.aif
	sound/direct_sound_samples/cries/mawile.aif
	sound/direct_sound_samples/cries/medicham.aif
	sound/direct_sound_samples/cries/meditite.aif
	sound/direct_sound_samples/cries/meganium.aif
	sound/direct_sound_samples/cries/meowth.aif
	sound/direct_sound_samples/cries/metagross.aif
	sound/direct_sound_samples/cries/metang.aif
	sound/direct_sound_samples/cries/metapod.aif
	sound/direct_sound_samples/cries/mew.aif
	sound/direct_sound_samples/cries/mewtwo.aif
	sound/direct_sound_samples/cries/mightyena.aif
	sound/direct_sound_samples/cries/milotic.aif
	sound/direct_sound_samples/cries/miltank.aif
	sound/direct_sound_samples/cries/minun.aif
	sound/direct_sound_samples/cries/misdreavus.aif
	sound/direct_sound_samples/cries/moltres.aif
	sound/direct_sound_samples/cries/mr_mime.aif
	sound/direct_sound_samples/cries/mudkip.aif
	sound/direct_sound_samples/cries/muk.aif
	sound/direct_sound_samples/cries/murkrow.aif
	sound/direct_sound_samples/cries/natu.aif
	sound/direct_sound_samples/cries/nidoking.aif
	sound/direct_sound_samples/cries/nidoqueen.aif
	sound/direct_sound_samples/cries/nidoran_f.aif
	sound/direct_sound_samples/cries/nidoran_m.aif
	sound/direct_sound_samples/cries/nidorina.aif
	sound/direct_sound_samples/cries/nidorino.aif
	sound/direct_sound_samples/cries/nincada.aif
	sound/direct_sound_samples/cries/ninetales.aif
	sound/direct_sound_samples/cries/ninjask.aif
	sound/direct_sound_samples/cries/noctowl.aif
	sound/direct_sound_samples/cries/nosepass.aif
	sound/direct_sound_samples/cries/numel.aif
	sound/direct_sound_samples/cries/nuzleaf.aif
	sound/direct_sound_samples/cries/octillery.aif
	sound/direct_sound_samples/cries/oddish.aif
	sound/direct_sound_samples/cries/omanyte.aif
	sound/direct_sound_samples/cries/omastar.aif
	sound/direct_sound_samples/cries/onix.aif
	sound/direct_sound_samples/cries/paras.aif
	sound/direct_sound_samples/cries/parasect.aif
	sound/direct_sound_samples/cries/pelipper.aif
	sound/direct_sound_samples/cries/persian.aif
	sound/direct_sound_samples/cries/phanpy.aif
	sound/direct_sound_samples/cries/pichu.aif
	sound/direct_sound_samples/cries/pidgeot.aif
	sound/direct_sound_samples/cries/pidgeotto.aif
	sound/direct_sound_samples/cries/pidgey.aif
	sound/direct_sound_samples/cries/pikachu.aif
	sound/direct_sound_samples/cries/piloswine.aif
	sound/direct_sound_samples/cries/pineco.aif
	sound/direct_sound_samples/cries/pinsir.aif
	sound/direct_sound_samples/cries/plusle.aif
	sound/direct_sound_samples/cries/politoed.aif
	sound/direct_sound_samples/cries/poliwag.aif
	sound/direct_sound_samples/cries/poliwhirl.aif
	sound/direct_sound_samples/cries/poliwrath.aif
	sound/direct_sound_samples/cries/ponyta.aif
	sound/direct_sound_samples/cries/poochyena.aif
	sound/direct_sound_samples/cries/porygon.aif
	sound/direct_sound_samples/cries/porygon2.aif
	sound/direct_sound_samples/cries/primeape.aif
	sound/direct_sound_samples/cries/psyduck.aif
	sound/direct_sound_samples/cries/pupitar.aif
	sound/direct_sound_samples/cries/quagsire.aif
	sound/direct_sound_samples/cries/quilava.aif
	sound/direct_sound_samples/cries/qwilfish.aif
	sound/direct_sound_samples/cries/raichu.aif
	sound/direct_sound_samples/cries/raikou.aif
	sound/direct_sound_samples/cries/ralts.aif
	sound/direct_sound_samples/cries/rapidash.aif
	sound/direct_sound_samples/cries/raticate.aif
	sound/direct_sound_samples/cries/rattata.aif
	sound/direct_sound_samples/cries/rayquaza.aif
	sound/direct_sound_samples/cries/regice.aif
	sound/direct_sound_samples/cries/regirock.aif
	sound/direct_sound_samples/cries/registeel.aif
	sound/direct_sound_samples/cries/relicanth.aif
	sound/direct_sound_samples/cries/remoraid.aif
	sound/direct_sound_samples/cries/rhydon.aif
	sound/direct_sound_samples/cries/rhyhorn.aif
	sound/direct_sound_samples/cries/roselia.aif
	sound/direct_sound_samples/cries/sableye.aif
	sound/direct_sound_samples/cries/salamence.aif
	sound/direct_sound_samples/cries/sandshrew.aif
	sound/direct_sound_samples/cries/sandslash.aif
	sound/direct_sound_samples/cries/sceptile.aif
	sound/direct_sound_samples/cries/scizor.aif
	sound/direct_sound_samples/cries/scyther.aif
	sound/direct_sound_samples/cries/seadra.aif
	sound/direct_sound_samples/cries/seaking.aif
	sound/direct_sound_samples/cries/sealeo.aif
	sound/direct_sound_samples/cries/seedot.aif
	sound/direct_sound_samples/cries/seel.aif
	sound/direct_sound_samples/cries/sentret.aif
	sound/direct_sound_samples/cries/seviper.aif
	sound/direct_sound_samples/cries/sharpedo.aif
	sound/direct_sound_samples/cries/shedinja.aif
	sound/direct_sound_samples/cries/shelgon.aif
	sound/direct_sound_samples/cries/shellder.aif
	sound/direct_sound_samples/cries/shiftry.aif
	sound/direct_sound_samples/cries/shroomish.aif
	sound/direct_sound_samples/cries/shuckle.aif
	sound/direct_sound_samples/cries/shuppet.aif
	sound/direct_sound_samples/cries/silcoon.aif
	sound/direct_sound_samples/cries/skarmory.aif
	sound/direct_sound_samples/cries/skiploom.aif
	sound/direct_sound_samples/cries/skitty.aif
	sound/direct_sound_samples/cries/slaking.aif
	sound/direct_sound_samples/cries/slakoth.aif
	sound/direct_sound_samples/cries/slowbro.aif
	sound/direct_sound_samples/cries/slowking.aif
	sound/direct_sound_samples/cries/slowpoke.aif
	sound/direct_sound_samples/cries/slugma.aif
	sound/direct_sound_samples/cries/smeargle.aif
	sound/direct_sound_samples/cries/smoochum.aif
	sound/direct_sound_samples/cries/sneasel.aif
	sound/direct_sound_samples/cries/snorlax.aif
	sound/direct_sound_samples/cries/snorunt.aif
	sound/direct_sound_samples/cries/snubbull.aif
	sound/direct_sound_samples/cries/solrock.aif
	sound/direct_sound_samples/cries/spearow.aif
	sound/direct_sound_samples/cries/spheal.aif
	sound/direct_sound_samples/cries/spinarak.aif
	sound/direct_sound_samples/cries/spinda.aif
	sound/direct_sound_samples/cries/spoink.aif
	sound/direct_sound_samples/cries/squirtle.aif
	sound/direct_sound_samples/cries/stantler.aif
	sound/direct_sound_samples/cries/starmie.aif
	sound/direct_sound_samples/cries/staryu.aif
	sound/direct_sound_samples/cries/steelix.aif
	sound/direct_sound_samples/cries/sudowoodo.aif
	sound/direct_sound_samples/cries/suicune.aif
	sound/direct_sound_samples/cries/sunflora.aif
	sound/direct_sound_samples/cries/sunkern.aif
	sound/direct_sound_samples/cries/surskit.aif
	sound/direct_sound_samples/cries/swablu.aif
	sound/direct_sound_samples/cries/swalot.aif
	sound/direct_sound_samples/cries/swampert.aif
	sound/direct_sound_samples/cries/swellow.aif
	sound/direct_sound_samples/cries/swinub.aif
	sound/direct_sound_samples/cries/taillow.aif
	sound/direct_sound_samples/cries/tangela.aif
	sound/direct_sound_samples/cries/tauros.aif
	sound/direct_sound_samples/cries/teddiursa.aif
	sound/direct_sound_samples/cries/tentacool.aif
	sound/direct_sound_samples/cries/tentacruel.aif
	sound/direct_sound_samples/cries/togepi.aif
	sound/direct_sound_samples/cries/togetic.aif
	sound/direct_sound_samples/cries/torchic.aif
	sound/direct_sound_samples/cries/torkoal.aif
	sound/direct_sound_samples/cries/totodile.aif
	sound/direct_sound_samples/cries/trapinch.aif
	sound/direct_sound_samples/cries/treecko.aif
	sound/direct_sound_samples/cries/tropius.aif
	sound/direct_sound_samples/cries/typhlosion.aif
	sound/direct_sound_samples/cries/tyranitar.aif
	sound/direct_sound_samples/cries/tyrogue.aif
	sound/direct_sound_samples/cries/umbreon.aif
	sound/direct_sound_samples/cries/unown.aif
	sound/direct_sound_samples/cries/ursaring.aif
	sound/direct_sound_samples/cries/vaporeon.aif
	sound/direct_sound_samples/cries/venomoth.aif
	sound/direct_sound_samples/cries/venonat.aif
	sound/direct_sound_samples/cries/venusaur.aif
	sound/direct_sound_samples/cries/vibrava.aif
	sound/direct_sound_samples/cries/victreebel.aif
	sound/direct_sound_samples/cries/vigoroth.aif
	sound/direct_sound_samples/cries/vileplume.aif
	sound/direct_sound_samples/cries/volbeat.aif
	sound/direct_sound_samples/cries/voltorb.aif
	sound/direct_sound_samples/cries/vulpix.aif
	sound/direct_sound_samples/cries/wailmer.aif
	sound/direct_sound_samples/cries/wailord.aif
	sound/direct_sound_samples/cries/walrein.aif
	sound/direct_sound_samples/cries/wartortle.aif
	sound/direct_sound_samples/cries/weedle.aif
	sound/direct_sound_samples/cries/weepinbell.aif
	sound/direct_sound_samples/cries/weezing.aif
	sound/direct_sound_samples/cries/whiscash.aif
	sound/direct_sound_samples/cries/whismur.aif
	sound/direct_sound_samples/cries/wigglytuff.aif
	sound/direct_sound_samples/cries/wingull.aif
	sound/direct_sound_samples/cries/wobbuffet.aif
	sound/direct_sound_samples/cries/wooper.aif
	sound/direct_sound_samples/cries/wurmple.aif
	sound/direct_sound_samples/cries/wynaut.aif
	sound/direct_sound_samples/cries/xatu.aif
	sound/direct_sound_samples/cries/yanma.aif
	sound/direct_sound_samples/cries/zangoose.aif
	sound/direct_sound_samples/cries/zapdos.aif
	sound/direct_sound_samples/cries/zigzagoon.aif
	sound/direct_sound_samples/cries/zubat.aif
This commit is contained in:
Hedara 2025-12-01 16:46:34 +01:00
commit 4ba3932174
2563 changed files with 1424 additions and 1157 deletions

View File

@ -206,7 +206,7 @@ include make_tools.mk
SMOLTM := $(TOOLS_DIR)/compresSmol/compresSmolTilemap$(EXE)
SMOL := $(TOOLS_DIR)/compresSmol/compresSmol$(EXE)
GFX := $(TOOLS_DIR)/gbagfx/gbagfx$(EXE)
AIF := $(TOOLS_DIR)/aif2pcm/aif2pcm$(EXE)
WAV2AGB := $(TOOLS_DIR)/wav2agb/wav2agb$(EXE)
MID := $(TOOLS_DIR)/mid2agb/mid2agb$(EXE)
SCANINC := $(TOOLS_DIR)/scaninc/scaninc$(EXE)
PREPROC := $(TOOLS_DIR)/preproc/preproc$(EXE)
@ -421,7 +421,7 @@ generated: $(AUTO_GEN_TARGETS)
%.s: ;
%.png: ;
%.pal: ;
%.aif: ;
%.wav: ;
%.1bpp: %.png ; $(GFX) $< $@
%.4bpp: %.png ; $(GFX) $< $@

View File

@ -20,16 +20,17 @@ $(MID_BUILDDIR)/%.o: $(MID_ASM_DIR)/%.s
$(AS) $(ASFLAGS) -I sound -o $@ $<
# Compressed cries
$(CRY_BIN_DIR)/%.bin: $(CRY_SUBDIR)/%.aif
$(AIF) $< $@ --compress
$(CRY_BIN_DIR)/%.bin: $(CRY_SUBDIR)/%.wav
# NOTE: If using ipatix's High Quality Audio Mixer, remove "--no-pad" below.
$(WAV2AGB) -b -c -l 1 --no-pad $< $@
# Uncompressed cries
$(CRY_BIN_DIR)/uncomp_%.bin: $(CRY_SUBDIR)/uncomp_%.aif
$(AIF) $< $@
# Uncompressed sounds
$(SOUND_BIN_DIR)/%.bin: sound/%.aif
$(AIF) $< $@
$(SOUND_BIN_DIR)/%.bin: sound/%.wav
$(WAV2AGB) -b $< $@
# For each line in midi.cfg, we do some trickery to convert it into a make rule for the `.mid` file described on the line
# Data following the colon in said file corresponds to arguments passed into mid2agb

View File

@ -5,7 +5,7 @@ MAKEFLAGS += --no-print-directory
# Inclusive list. If you don't want a tool to be built, don't add it here.
TOOLS_DIR := tools
TOOL_NAMES := aif2pcm bin2c gbafix gbagfx jsonproc mapjson mid2agb preproc ramscrgen rsfont scaninc trainerproc compresSmol
TOOL_NAMES := bin2c gbafix gbagfx jsonproc mapjson mid2agb preproc ramscrgen rsfont scaninc trainerproc compresSmol wav2agb
CHECK_TOOL_NAMES = patchelf mgba-rom-test-hydra
TOOLDIRS := $(TOOL_NAMES:%=$(TOOLS_DIR)/%)

View File

@ -0,0 +1,301 @@
#!/usr/bin/env python3
"""
Converts .bin audio files (GBA format) to .wav files.
Reads the binary format created by aif2pcm and generates WAV files
that will produce identical binaries when processed by wav2agb -b.
"""
import struct
import sys
import os
from typing import Optional
# Delta encoding table used for compression/decompression
# Matches the table in tools/aif2pcm/main.c
DELTA_ENCODING_TABLE = [
0, 1, 4, 9, 16, 25, 36, 49,
-64, -49, -36, -25, -16, -9, -4, -1,
]
def delta_decompress(compressed_data: bytes, expected_length: int) -> bytes:
"""
Decompress delta-encoded audio data.
Delta compression format (from tools/aif2pcm/main.c):
- Data is organized in blocks of up to 64 samples each
- Each block starts with a base sample value (1 byte)
- Followed by a delta index (4 bits) for the second sample
- Then 31 pairs of delta indices (4 bits each, packed into bytes)
- Delta indices reference DELTA_ENCODING_TABLE to get the actual delta value
Args:
compressed_data: The compressed audio data
expected_length: Expected length of decompressed data
Returns:
Decompressed audio data as bytes
"""
pcm = bytearray(expected_length + 0x40) # Extra buffer space
i = 0 # Input position
j = 0 # Output position
while i < len(compressed_data) and j < expected_length:
# Read base sample for this block
base = compressed_data[i]
# Convert to signed int8 for calculations
base_signed = base if base < 128 else base - 256
pcm[j] = base
i += 1
j += 1
if i >= len(compressed_data) or j >= expected_length:
break
# Read second sample using low nibble delta
lo = compressed_data[i] & 0xf
base_signed += DELTA_ENCODING_TABLE[lo]
pcm[j] = base_signed & 0xff
i += 1
j += 1
if i >= len(compressed_data) or j >= expected_length:
break
# Process up to 31 pairs of samples (62 samples total)
for k in range(31):
# High nibble
hi = (compressed_data[i] >> 4) & 0xf
base_signed += DELTA_ENCODING_TABLE[hi]
pcm[j] = base_signed & 0xff
j += 1
if j >= expected_length:
break
# Low nibble
lo = compressed_data[i] & 0xf
base_signed += DELTA_ENCODING_TABLE[lo]
pcm[j] = base_signed & 0xff
j += 1
i += 1
if i >= len(compressed_data):
break
if j >= expected_length:
break
if j >= expected_length:
break
return bytes(pcm[:j])
def read_bin(bin_path: str) -> tuple:
"""
Read a GBA audio .bin file and extract all data.
Binary format (little-endian):
- Bytes 0-3: flags (bit 0 = compression, bit 30 = loop enabled)
- Bytes 4-7: pitch value = sample_rate * 1024
- Bytes 8-11: loop start position
- Bytes 12-15: loop end position (stored as actual_end - 1)
- Remaining bytes: audio samples (8-bit signed)
"""
with open(bin_path, 'rb') as f:
bin_data = f.read()
if len(bin_data) < 16:
raise ValueError(f"File too small: {len(bin_data)} bytes")
# Read header
flags = struct.unpack('<I', bin_data[0:4])[0]
pitch_value = struct.unpack('<I', bin_data[4:8])[0]
loop_start = struct.unpack('<I', bin_data[8:12])[0]
loop_end_stored = struct.unpack('<I', bin_data[12:16])[0]
# Extract flags
is_compressed = (flags & 0x01) != 0
is_looped = (flags & 0x40000000) != 0
# Calculate sample rate from pitch value
sample_rate = pitch_value / 1024.0
# Loop end is stored as (actual_end - 1) in binary format
# For the expected number of samples, we add 1
expected_num_samples = loop_end_stored + 1
# Read sample data (8-bit signed)
compressed_data = bin_data[16:]
if is_compressed:
# Decompress the data
# Note: delta_decompress may return fewer samples than expected if
# the compressed data is shorter (this matches aif2pcm behavior)
samples = delta_decompress(compressed_data, expected_num_samples)
# Pad samples to expected length if needed (matching aif2pcm behavior)
# This can happen when the compressed data is slightly short
if len(samples) < expected_num_samples:
# Pad with the last sample value
last_sample = samples[-1] if len(samples) > 0 else 0
padding = bytes([last_sample] * (expected_num_samples - len(samples)))
samples = samples + padding
else:
# For uncompressed data, only read expected_num_samples
# (ignore any trailing alignment padding in the .bin file)
samples = compressed_data[:expected_num_samples]
# For loop_end, use the expected number from the header
# This matches aif2pcm's behavior where the COMM chunk has the expected count
# even if the actual SSND data is shorter
loop_end = expected_num_samples if is_looped else 0
return sample_rate, is_looped, loop_start, loop_end, samples
def write_wav(wav_path: str, sample_rate: float, is_looped: bool,
loop_start: int, loop_end: int, samples: bytes):
"""
Write a .wav file with smpl chunk.
"""
# WAV uses unsigned 8-bit, GBA bin uses signed 8-bit
# Convert signed (-128 to +127) to unsigned (0 to 255)
samples_unsigned = bytes((b + 128) & 0xFF for b in samples)
# For WAV fmt chunk, use integer sample rate
sample_rate_int = int(sample_rate)
num_channels = 1
bytes_per_sample = 1
bits_per_sample = 8
byte_rate = sample_rate_int * num_channels * bytes_per_sample
block_align = num_channels * bytes_per_sample
# Build fmt chunk
fmt_chunk = struct.pack('<HHIIHH',
1, # Audio format (1 = PCM)
num_channels, # Number of channels
sample_rate_int, # Sample rate (integer)
byte_rate, # Byte rate
block_align, # Block align
bits_per_sample # Bits per sample
)
# Build smpl chunk
sample_period = int(1000000000.0 / sample_rate)
# MIDI note: default to 60 (C4) since we don't have this info in the bin
midi_note = 60
smpl_chunk = struct.pack('<IIIIIIII',
0, # Manufacturer
0, # Product
sample_period, # Sample period (nanoseconds)
midi_note, # MIDI unity note
0, # MIDI pitch fraction
0, # SMPTE format
0, # SMPTE offset
1 if is_looped else 0 # Num sample loops
)
smpl_chunk += struct.pack('<I', 0) # Sampler data
# Add loop structure if loop exists
if is_looped:
# Loop end in binary is stored as (end - 1), so we already added 1 above
loop_end_inclusive = loop_end - 1
smpl_chunk += struct.pack('<IIIIII',
0, # Cue point ID
0, # Type (0 = forward loop)
loop_start, # Start
loop_end_inclusive, # End (inclusive)
0, # Fraction
0 # Play count (0 = infinite)
)
# Build custom 'agbp' (AGB Pitch) chunk to store exact pitch value
# This avoids precision loss from period-based round-trip
# pitch_value = sample_rate * 1024 (GBA format)
pitch_value_int = int(sample_rate * 1024.0)
agbp_chunk = struct.pack('<I', pitch_value_int)
# Calculate sizes
data_chunk_size = len(samples_unsigned)
fmt_chunk_size = len(fmt_chunk)
smpl_chunk_size = len(smpl_chunk)
agbp_chunk_size = len(agbp_chunk)
# RIFF chunk size
riff_size = 4 + 8 + fmt_chunk_size + 8 + smpl_chunk_size + 8 + agbp_chunk_size + 8 + data_chunk_size
# Write WAV file
with open(wav_path, 'wb') as f:
# RIFF header
f.write(b'RIFF')
f.write(struct.pack('<I', riff_size))
f.write(b'WAVE')
# fmt chunk
f.write(b'fmt ')
f.write(struct.pack('<I', fmt_chunk_size))
f.write(fmt_chunk)
# smpl chunk
f.write(b'smpl')
f.write(struct.pack('<I', smpl_chunk_size))
f.write(smpl_chunk)
# agbp chunk (custom chunk for exact GBA pitch value)
f.write(b'agbp')
f.write(struct.pack('<I', agbp_chunk_size))
f.write(agbp_chunk)
# data chunk
f.write(b'data')
f.write(struct.pack('<I', data_chunk_size))
f.write(samples_unsigned)
def convert_bin_to_wav(bin_path: str, wav_path: Optional[str] = None):
"""Convert a single .bin file to .wav format"""
if wav_path is None:
wav_path = os.path.splitext(bin_path)[0] + '.wav'
print(f"Converting {bin_path} -> {wav_path}")
sample_rate, is_looped, loop_start, loop_end, samples = read_bin(bin_path)
print(f" Sample rate: {sample_rate} Hz")
print(f" Num samples: {len(samples)}")
if is_looped:
print(f" Loop: {loop_start} -> {loop_end}")
else:
print(f" Loop: None")
write_wav(wav_path, sample_rate, is_looped, loop_start, loop_end, samples)
print(f" Done!")
def main():
if len(sys.argv) < 2:
print("Usage: bin_to_wav.py <input.bin> [output.wav]")
print(" or: bin_to_wav.py <directory> (converts all .bin files in directory)")
sys.exit(1)
input_path = sys.argv[1]
if os.path.isdir(input_path):
# Convert all .bin files in directory
for filename in sorted(os.listdir(input_path)):
if filename.lower().endswith('.bin'):
bin_path = os.path.join(input_path, filename)
convert_bin_to_wav(bin_path)
else:
# Convert single file
output_path = sys.argv[2] if len(sys.argv) > 2 else None
convert_bin_to_wav(input_path, output_path)
if __name__ == '__main__':
main()

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More