diff --git a/Makefile b/Makefile index 64271e06170..f2c7d4bfd4f 100644 --- a/Makefile +++ b/Makefile @@ -109,6 +109,7 @@ MKDMADATA := tools/mkdmadata ELF2ROM := tools/elf2rom ZAPD := tools/ZAPD/ZAPD.out FADO := tools/fado/fado.elf +SEQ_ASM := tools/assemble_sequence ifeq ($(COMPILER),gcc) OPTFLAGS := -Os -ffast-math -fno-unsafe-math-optimizations @@ -158,7 +159,10 @@ else SRC_DIRS := $(shell find src -type d) endif -ASSET_BIN_DIRS := $(shell find assets/* -type d -not -path "assets/xml*" -not -path "assets/text") +ASSET_BIN_DIRS := $(shell find assets/code/* assets/misc/* assets/objects/* assets/overlays/* assets/scenes/* assets/textures/* -type d) +SEQUENCE_DIR := assets/sequences +SOUNDFONT_DIR := assets/soundfonts +SAMPLES_DIR := $(shell find assets/samples/* -type d) ASSET_FILES_XML := $(foreach dir,$(ASSET_BIN_DIRS),$(wildcard $(dir)/*.xml)) ASSET_FILES_BIN := $(foreach dir,$(ASSET_BIN_DIRS),$(wildcard $(dir)/*.bin)) ASSET_FILES_OUT := $(foreach f,$(ASSET_FILES_XML:.xml=.c),$f) \ @@ -168,10 +172,17 @@ ASSET_FILES_OUT := $(foreach f,$(ASSET_FILES_XML:.xml=.c),$f) \ UNDECOMPILED_DATA_DIRS := $(shell find data -type d) # source files +SEQ_FILES := $(foreach dir,$(SRC_DIRS) $(SEQUENCE_DIR),$(wildcard $(dir)/*.mus)) +FONT_FILES := $(foreach dir,$(SOUNDFONT_DIR),$(wildcard $(dir)/*.xml)) +AIFC_FILES := $(foreach dir,$(SAMPLES_DIR),$(wildcard $(dir)/*.aifc)) +INC_FILES := $(foreach f,$(SEQ_FILES:.mus=.inc),build/include/$f) +BANK_OUT := $(foreach dir,$(SAMPLES_DIR:.=.o),build/assets/samplebanks/$(dir)) +MUS_OUT := $(foreach f,$(SEQ_FILES:.mus=.o),build/$f) C_FILES := $(foreach dir,$(SRC_DIRS) $(ASSET_BIN_DIRS),$(wildcard $(dir)/*.c)) S_FILES := $(foreach dir,$(SRC_DIRS) $(UNDECOMPILED_DATA_DIRS),$(wildcard $(dir)/*.s)) O_FILES := $(foreach f,$(S_FILES:.s=.o),build/$f) \ $(foreach f,$(C_FILES:.c=.o),build/$f) \ + $(foreach f,$(FONT_FILES:.xml=.o),build/$f) \ $(foreach f,$(wildcard baserom/*),build/$f.o) OVL_RELOC_FILES := $(shell $(CPP) $(CPPFLAGS) $(SPEC) | grep -o '[^"]*_reloc.o' ) @@ -187,6 +198,7 @@ TEXTURE_FILES_OUT := $(foreach f,$(TEXTURE_FILES_PNG:.png=.inc.c),build/$f) \ $(foreach f,$(TEXTURE_FILES_JPG:.jpg=.jpg.inc.c),build/$f) \ # create build directories +$(shell mkdir -p build/baserom build/assets/text build/assets/data assets/sequences assets/soundfonts assets/samples) $(shell mkdir -p build/baserom build/assets/text $(foreach dir,$(SRC_DIRS) $(UNDECOMPILED_DATA_DIRS) $(ASSET_BIN_DIRS),build/$(dir))) ifeq ($(COMPILER),ido) @@ -246,6 +258,9 @@ clean: assetclean: $(RM) -r $(ASSET_BIN_DIRS) + $(RM) -r $(SOUNDFONT_DIR) + $(RM) $(shell find $(SEQUENCE_DIR)/*.seq -not -path "*.prg.seq") + $(RM) -r assets/samples/ $(RM) -r assets/text/*.h $(RM) -r build/assets $(RM) -r .extracted-assets.json @@ -259,6 +274,8 @@ setup: python3 fixbaserom.py python3 extract_baserom.py python3 extract_assets.py -j$(N_THREADS) + python3 tools/disassemble_sound.py MQDebug baserom/code baserom/Audiotable baserom/Audiobank assets/xml assets/samples assets/soundfonts build/include + python3 tools/disassemble_sequences.py MQDebug baserom/code baserom/Audioseq assets/xml/sequences/Sequences.xml build/include include/sequence.inc assets/sequences test: $(ROM) $(EMULATOR) $(EMU_FLAGS) $< @@ -271,7 +288,7 @@ test: $(ROM) $(ROM): $(ELF) $(ELF2ROM) -cic 6105 $< $@ -$(ELF): $(TEXTURE_FILES_OUT) $(ASSET_FILES_OUT) $(O_FILES) $(OVL_RELOC_FILES) build/ldscript.txt build/undefined_syms.txt +$(ELF): audio_tables $(TEXTURE_FILES_OUT) $(ASSET_FILES_OUT) $(O_FILES) $(MUS_OUT) $(OVL_RELOC_FILES) build/ldscript.txt build/undefined_syms.txt $(LD) -T build/undefined_syms.txt -T build/ldscript.txt --no-check-sections --accept-unknown-input-arch --emit-relocs -Map build/z64.map -o $@ ## Order-only prerequisites @@ -284,6 +301,8 @@ $(OVL_RELOC_FILES): | o_files asset_files: $(TEXTURE_FILES_OUT) $(ASSET_FILES_OUT) $(O_FILES): | asset_files +audio_tables: build/assets/data/SequenceTable.o build/assets/data/SoundFontTable.o + .PHONY: o_files asset_files build/$(SPEC): $(SPEC) @@ -343,6 +362,18 @@ build/src/overlays/%_reloc.o: build/$(SPEC) $(FADO) $$(tools/reloc_prereq $< $(notdir $*)) -n $(notdir $*) -o $(@:.o=.s) -M $(@:.o=.d) $(AS) $(ASFLAGS) $(@:.o=.s) -o $@ +build/assets/data/SequenceTable.o: $(MUS_OUT) + python3 tools/assemble_sequences.py $(SEQUENCE_DIR) build/include build + +build/assets/data/SoundFontTable.o: $(FONT_FILES) $(AIFC_FILES) + python3 tools/assemble_sound.py $(SOUNDFONT_DIR) build/assets build/include assets/samples --build-bank --match=ocarina + +build/%.o: %.seq + $(SEQ_ASM) $< $@ --font-path build/include --elf big 32 mips + +build/include/%.inc: $(FONT_FILES) + python3 tools/assemble_font_includes.py $(SOUNDFONT_DIR) build/include + build/%.inc.c: %.png $(ZAPD) btex -eh -tt $(subst .,,$(suffix $*)) -i $< -o $@ diff --git a/assets/.gitignore b/assets/.gitignore index e5633a6496a..511fc0a65dd 100644 --- a/assets/.gitignore +++ b/assets/.gitignore @@ -1,7 +1,27 @@ +# Raw binary files included with assets *.bin +# C code representing asset data *.c +# But not for text code !text/*.c +# Headers representing asset data *.h -*.cfg +# Vertex arrays *.vtx.inc +# Display lists *.dlist.inc +# Binary representation of a music sequence +*.aseq +# Music sequence +*.seq +# Uncompressed audio +*.aiff +# Compressed audio +*.aifc + +# XML indicating sequences that are purely references to other sequences +/sequences/References.xml +# Soundfont XMLs +/soundfonts/*.xml +# Sample Bank Descriptor XML +/samples/Banks.xml diff --git a/assets/sequences/000_Sound_Effects.prg.seq b/assets/sequences/000_Sound_Effects.prg.seq new file mode 100644 index 00000000000..0a8ffe0971d --- /dev/null +++ b/assets/sequences/000_Sound_Effects.prg.seq @@ -0,0 +1,1002 @@ +.desc title "Sound Effects" +.desc type "program" +.cache CACHE_PERMANENT +.usefont SOUNDFONT_SFX_2 +.usefont SOUNDFONT_SFX_1 + +.sequence sequence_start +mutebhv 0x60 +mutescale 0 +vol 127 +tempo 120 +initchan 0xFFF +ldchan 0, channel_player0 +ldchan 1, channel_player1 +ldchan 2, channel_player2 +ldchan 3, channel_item0 +ldchan 4, channel_item1 +ldchan 5, channel_env0 +ldchan 6, channel_env1 +ldchan 7, channel_env2 +ldchan 8, channel_enemy0 +ldchan 9, channel_enemy1 +ldchan 10, channel_enemy2 +ldchan 11, channel_system +ldchan 12, channel_system +ldchan 13, channel_ocarina +ldchan 14, channel_voice0 +ldchan 15, channel_voice1 +.sequence seq_loop +delay 32720 +rjump seq_loop + +# Delay for a number of ticks (1-255) in an interruptible manner. +.channel delay +stseq 0, @+1 +loop 20 +rjump delay_iter + +# Delay for a number of ticks (1-255) in an interruptible manner, +# with volume controlled by io port 2 and filter by port 3. +.channel delay_varyingvol +stseq 0, @+1 +loop 20 +ldio 3 +stseq 0, @+1 +filter 0 +ldio 2 +rbltz delay_iter +stseq 0, @+1 +vol 127 +.channel delay_iter +delay1 +ldio 0 +stio 0 # ports 0 and 1 are reset to -1 when read; restore the value +sub 255 +rbeqz delay_skip +rjump delay_interrupt +.channel delay_skip +loopend +end +.channel delay_interrupt +ldio 0 +stio 0 # ports 0 and 1 are reset to -1 when read; restore the value +break # break out of the loop +break # force the caller to return immediately +dellayer 0 +dellayer 1 +dellayer 2 +dellayer 3 +end + +.channel setup_chan_common +noshort +mutebhv 0x20 +effects 128 +notepri 14 +rvrbidx 1 +end + +.channel start_playing_common +dellayer 0 +dellayer 1 +ldi 0 +gain 0 +stio 1 # set status = 0 (playing) +end + +.channel varyvol +ldio 2 +rbltz varyvol_skip +stseq 0, @+1 +vol 127 +.channel varyvol_skip +end + +# Main loop for BANK_PLAYER +.channel channel_player0 +ldfilter filter_player0 +rjump channel_player + +.channel channel_player1 +ldfilter filter_player1 +rjump channel_player + +.channel channel_player2 +ldfilter filter_player2 + +.channel channel_player +call setup_chan_common +filter 0 +font SOUNDFONT_SFX_1 +panweight 127 + +.channel main_loop_player +delay1 +ldio 0 +sub 1 +beqz start_playing_player +jump main_loop_player + +.channel start_playing_player +call start_playing_common +dellayer 2 +vibdepth 0 +ldio 4 # read sound id from port 4 +bgez part1_player +and 127 +dyntbl table_player_old +jump use_table_player + +.channel part1_player +dyntbl table_player_kid + +.channel use_table_player +dyncall + +.channel poll_player +ldio 3 +stseq 0, @+1 +filter 15 +call varyvol +delay1 +ldio 0 +rbeqz force_stop_player # told to stop +rbltz skip_player +rjump start_playing_player # told to play something else + +.channel skip_player +testlayer 0 +rbeqz poll_player # if layer 0 hasn't finished, keep polling +ldi 255 +stio 1 # set status = -1 (stopped) + +.channel force_stop_player +dellayer 0 +dellayer 1 +dellayer 2 +rjump main_loop_player + +.include "sfxbanks/player.seq.inc" + +# Main loop for BANK_ITEM +.channel channel_item0 +ldfilter filter_item0 +rjump channel_item + +.channel channel_item1 +ldfilter filter_item1 + +.channel channel_item +dyntbl table_item +call setup_chan_common +font SOUNDFONT_SFX_1 +panweight 127 +filter 0 + +.channel main_loop_item +delay1 +ldio 0 +sub 1 +rbeqz start_playing_item +rjump main_loop_item + +.channel start_playing_item +call start_playing_common +dellayer 2 +vibdepth 0 +ldio 4 +dyncall + +.channel poll_item +ldio 3 +stseq 0, @+1 +filter 15 +call varyvol +delay1 +ldio 0 +rbeqz force_stop_item +rbltz skip_item +rjump start_playing_item + +.channel skip_item +testlayer 0 +rbeqz poll_item +ldi 255 +stio 1 + +.channel force_stop_item +dellayer 0 +dellayer 1 +dellayer 2 +ldi 0 +rjump main_loop_item + +.include "sfxbanks/item.seq.inc" + +# Main loop for BANK_ENV +.channel channel_env0 +ldfilter filter_env0 +rjump channel_env + +.channel channel_env1 +ldfilter filter_env1 +rjump channel_env + +.channel channel_env2 +ldfilter filter_env2 + +.channel channel_env +call setup_chan_common +font SOUNDFONT_SFX_1 +filter 0 +vibdelay 0 + +.channel main_loop_env +delay1 +ldio 0 +sub 1 +rbeqz start_playing_env +rjump main_loop_env + +.channel start_playing_env +vibdepth 0 +notealloc 0 +freenotelist +panweight 127 +call start_playing_common +dellayer 2 +ldio 4 +bgez part1_env +and 127 +dyntbl table_env+0x100 +rjump use_table_env + +.channel part1_env +dyntbl table_env + +.channel use_table_env +dyncall + +.channel poll_env +ldio 3 +stseq 0, @+1 +filter 0 +call varyvol +delay1 +ldio 0 +rbeqz force_stop_env +rbltz skip_env +rjump start_playing_env + +.channel skip_env +testlayer 0 +rbeqz poll_env +ldi 255 +stio 1 + +.channel force_stop_env +dellayer 0 +dellayer 1 +dellayer 2 +rjump main_loop_env + +.include "sfxbanks/env.seq.inc" + +# Main loop for BANK_ENEMY +.channel channel_enemy0 +ldfilter filter_enemy0 +rjump channel_enemy + +.channel channel_enemy1 +ldfilter filter_enemy1 +rjump channel_enemy + +.channel channel_enemy2 +ldfilter filter_enemy2 + +.channel channel_enemy +call setup_chan_common +font SOUNDFONT_SFX_2 +filter 0 + +.channel main_loop_enemy +delay1 +ldio 0 +sub 1 +beqz start_playing_enemy +jump main_loop_enemy + +.channel start_playing_enemy +call start_playing_common +dellayer 2 +dellayer 3 +vibdepth 0 +gain 0 +panweight 127 +ldio 5 +sub 1 +rbeqz part3or4_enemy +ldio 4 +bgez part1_enemy +and 127 +dyntbl table_enemy+0x100 +rjump use_table_enemy + +.channel part3or4_enemy +dyntbl table_enemy+0x200 +ldio 4 +bgez use_table_enemy +and 127 +dyntbl table_enemy+0x300 +rjump use_table_enemy + +.channel part1_enemy +dyntbl table_enemy + +.channel use_table_enemy +env envelope_6A7C +releaserate 251 +dyncall + +.channel poll_enemy +ldio 3 +stseq 0, @+1 +filter 15 +call varyvol +delay1 +ldio 0 +rbeqz force_stop_enemy +rbltz skip_enemy +rjump start_playing_enemy + +.channel skip_enemy +testlayer 0 +rbeqz poll_enemy +ldi 255 +stio 1 + +.channel force_stop_enemy +dellayer 0 +dellayer 1 +dellayer 2 +dellayer 3 +rjump main_loop_enemy + +.include "sfxbanks/enemy.seq.inc" + +# Main loop for BANK_SYSTEM +.channel channel_system +dyntbl table_system +noshort +mutebhv 0x0 +notepri 14 +rvrbidx 1 +effects 0 +font SOUNDFONT_SFX_1 +panweight 0 +.channel main_loop_system +delay1 +ldio 0 +sub 1 +beqz start_playing_system +jump main_loop_system + +.channel start_playing_system +reverb 0 +call start_playing_common +dellayer 2 +ldio 4 +dyncall + +.channel poll_system +call varyvol +delay1 +ldio 0 +rbeqz force_stop_system +rbltz skip_system +rjump start_playing_system + +.channel skip_system +testlayer 0 +beqz poll_system +ldi 255 +stio 1 + +.channel force_stop_system +dellayer 0 +dellayer 1 +dellayer 2 +rjump main_loop_system + +.include "sfxbanks/system.seq.inc" + +# Main loop for BANK_OCARINA +.channel channel_ocarina +dyntbl table_ocarina +noshort +font SOUNDFONT_SFX_1 +panweight 127 +mutebhv 0x0 +effects 128 +notepri 14 + +.channel main_loop_ocarina +delay1 +ldio 1 +rbltz reservenotes_skip_ocarina # -1 => maintain old reservation status +rbeqz unreservenotes_ocarina # 0 => unreserve notes +allocnotelist 1 # 1 => reserve notes +notealloc 2 +rjump reservenotes_skip_ocarina + +.channel unreservenotes_ocarina +freenotelist +notealloc 0 + +.channel reservenotes_skip_ocarina +ldio 0 +sub 1 +rbeqz start_playing_ocarina +rjump main_loop_ocarina + +.channel start_playing_ocarina +vibdepth 0 +rvrbidx 0 +dellayer 0 +ldi 0 +stio 6 +ldio 4 +dyncall + +.channel poll_ocarina +ldio 2 +rbltz changevol_skip_ocarina +stseq 0, @+1 +vol 127 + +.channel changevol_skip_ocarina +delay1 +ldio 0 +rbeqz force_stop_ocarina +rbltz skip_ocarina +rjump start_playing_ocarina + +.channel skip_ocarina +testlayer 0 +rbeqz poll_ocarina +ldi 255 +stio 1 # set status = -1 (finished) + +.channel force_stop_ocarina +dellayer 0 +rjump main_loop_ocarina + +.include "sfxbanks/ocarina.seq.inc" + +# Main loop for BANK_VOICE +.channel channel_voice0 +ldfilter filter_voice0 +rjump channel_voice + +.channel channel_voice1 +ldfilter filter_voice1 + +.channel channel_voice +call setup_chan_common +instr FONTANY_INSTR_SFX +env envelope_65D0 +releaserate 251 +bend 0 +filter 0 +effects 128 +allocnotelist 1 + +.channel main_loop_voice +delay1 +ldio 0 +sub 1 +rbeqz start_playing_voice +rjump main_loop_voice + +.channel start_playing_voice +dellayer 0 +dellayer 1 +ldi 0 +stio 1 # set status = 0 (playing) +ldio 4 # read sound id from port 4 +bgez part1_voice +and 127 +dyntbl table_voice+0x100 +rjump use_table_voice + +.channel part1_voice +dyntbl table_voice + +.channel use_table_voice +dyncall + +.channel poll_voice +ldio 3 +stseq 0, @+1 +filter 15 +call varyvol +delay1 +ldio 0 +rbeqz force_stop_voice +rbltz skip_voice +rjump start_playing_voice + +.channel skip_voice +testlayer 0 +rbeqz poll_voice +ldi 255 +stio 1 # set status = -1 (finished) + +.channel force_stop_voice +dellayer 0 +dellayer 1 +rjump main_loop_voice + +.include "sfxbanks/voice.seq.inc" + +.envelope envelope_65D0 +point 1, 32700 +hang + +.envelope envelope_65D8 +point 1, 32700 +point 100, 30000 +point 200, 5000 +hang + +.envelope envelope_65E8 +point 1, 32700 +point 25, 25000 +point 100, 25000 +point 200, 5000 +hang + +.envelope envelope_65FC +point 1, 32700 +point 100, 30000 +point 250, 30000 +point 200, 5000 +hang + +.envelope envelope_6610 +point 1, 32700 +point 50, 30000 +point 100, 10000 +point 100, 0 +hang + +.envelope envelope_6624 +point 1, 32700 +point 30, 30000 +point 50, 10000 +point 50, 0 +hang + +.envelope envelope_6638 +point 1, 32700 +point 70, 30000 +point 120, 10000 +point 120, 0 +hang + +.envelope envelope_664C +point 1, 32700 +point 15, 32700 +point 15, 22000 +point 100, 15000 +hang + +.envelope envelope_6660 +point 1, 32700 +point 8, 32700 +point 8, 22000 +point 100, 15000 +hang + +.envelope envelope_6674 +point 10, 32700 +hang + +.envelope envelope_667C +point 30, 10000 +point 30, 32700 +hang + +.envelope envelope_6688 +point 20, 15000 +point 10, 32700 +hang + +.envelope envelope_6694 +point 48, 10000 +point 32, 32700 +hang + +.envelope envelope_66A0 +point 47, 15000 +point 13, 32700 +point 72, 10000 +hang + +.envelope envelope_66B0 +point 6, 32700 +hang + +.envelope envelope_66B8 +point 20, 32700 +point 50, 10000 +point 40, 0 +hang + +.envelope envelope_66C8 +point 18, 32700 +hang + +.envelope envelope_66D0 +point 10, 32700 +point 240, 31000 +point 150, 2000 +hang + +.envelope envelope_66E0 +point 14, 15000 +point 13, 32700 +hang + +.envelope envelope_66EC +point 40, 32700 +hang + +.envelope envelope_66F4 +point 400, 32700 +hang + +.envelope envelope_66FC +point 100, 32700 +hang + +.envelope envelope_6704 +point 225, 32700 +point 30, 30000 +hang + +.envelope envelope_6710 +point 200, 32700 +hang + +.envelope envelope_6718 +point 3, 32700 +hang + +.envelope envelope_6720 +point 12, 32700 +point 40, 5000 +hang + +.envelope envelope_unused_672C +point 10, 32700 +point 4, 20000 +point 4, 10000 +point 50, 2000 +hang + +.envelope envelope_6740 +point 40, 32700 +point 150, 32700 +point 300, 0 +hang + +.envelope envelope_6750 +point 40, 32700 +point 800, 32700 +point 100, 16000 +point 100, 32700 +point 100, 16000 +point 100, 32700 +point 100, 16000 +point 100, 32700 +point 600, 0 +hang + +.envelope envelope_6778 +point 200, 32700 +point 100, 16000 +point 100, 32700 +point 100, 16000 +point 100, 32700 +point 600, 0 +hang + +.envelope envelope_6794 +point 35, 32700 +point 40, 32700 +point 105, 0 +hang + +.envelope envelope_67A4 +point 1, 25000 +point 12, 32700 +point 40, 32700 +point 60, 15000 +point 80, 5000 +hang + +.envelope envelope_67BC +point 10, 32700 +point 50, 32700 +point 60, 5000 +hang + +.envelope envelope_67CC +point 200, 32700 +point 340, 0 +hang + +.envelope envelope_67D8 +point 400, 32700 +point 400, 20000 +goto 0 + +.envelope envelope_67E4 +point 1400, 32700 +point 400, 14000 +point 400, 32700 +goto 1 + +.envelope envelope_67F4 +point 25, 32700 +point 490, 12000 +hang + +.envelope envelope_6800 +point 100, 32700 +point 450, 32700 + +.envelope envelope_6808 +point 150, 32700 +point 1200, 32700 +point 400, 20000 +hang + +.envelope envelope_6818 +point 200, 32700 +point 200, 20000 +goto 0 + +.envelope envelope_6824 +point 2, 25000 +hang + +.envelope envelope_682C +point 1, 32700 +point 100, 30000 +point 200, 5000 +hang + +.envelope envelope_683C +point 1, 32700 +point 100, 30000 +point 100, 0 +hang + +.envelope envelope_684C +point 50, 32700 +point 160, 30000 +point 100, 0 +hang + +.envelope envelope_unused_685C +point 50, 32700 +point 100, 30000 +point 200, 20000 +hang + +.envelope envelope_686C +point 20, 32700 +point 100, 30000 +point 200, 20000 +hang + +.envelope envelope_687C +point 1, 32700 +point 100, 30000 +point 200, 20000 +hang + +.envelope envelope_688C +point 10, 32700 +point 250, 32700 +point 100, 20000 +hang + +.envelope envelope_unused_689C +point 15, 32700 +point 55, 20000 +point 15, 5000 +hang + +.envelope envelope_68AC +point 150, 32700 +hang + +.envelope envelope_68B4 +point 120, 32700 +hang + +.envelope envelope_68BC +point 60, 32700 +point 250, 32700 +point 100, 20000 +hang + +.envelope envelope_68CC +point 25, 32700 +point 100, 32700 +point 20, 2000 +hang + +.envelope envelope_68DC +point 1, 32700 +point 50, 32700 +point 25, 16000 +hang + +.envelope envelope_68EC +point 1, 32700 +point 80, 32700 +point 25, 16000 +hang + +.envelope envelope_68FC +point 1, 32700 +point 20, 32700 +point 7, 16000 +hang + +.envelope envelope_690C +point 1, 32700 +point 19, 32700 +point 5, 2000 +hang + +.envelope envelope_unused_691C +point 1, 32700 +point 50, 32700 +point 25, 10000 +hang + +.envelope envelope_692C +point 1, 32700 +point 50, 32700 +point 20, 1000 +hang + +.envelope envelope_unused_693C +point 1, 32700 +point 40, 32700 +point 10, 1000 +hang + +.envelope envelope_694C +point 1, 32700 +point 70, 32700 +point 10, 5000 +hang + +.envelope envelope_695C +point 1, 32700 +point 19, 32700 +point 5, 3000 +hang + +.envelope envelope_696C +point 1, 32700 +point 65, 32700 +point 20, 1000 +hang + +.envelope envelope_697C +point 1, 32700 +point 15, 32700 +point 2, 1000 +hang + +.envelope envelope_698C +point 1, 32700 +point 250, 32700 +point 60, 16000 +hang + +.envelope envelope_699C +point 1, 32700 +point 200, 32700 +point 50, 16000 +hang + +.envelope envelope_69AC +point 1, 32700 +point 260, 32700 +point 60, 16000 +hang + +.envelope envelope_69BC +point 1, 32700 +point 300, 32700 +point 60, 16000 +hang + +.envelope envelope_69CC +point 1, 32700 +point 350, 32700 +point 150, 16000 +hang + +.envelope envelope_69DC +point 1, 32700 +point 150, 32700 +point 100, 16000 +hang + +.envelope envelope_unused_69EC +point 1, 32700 +point 100, 32700 +point 40, 3000 +hang + +.envelope envelope_69FC +point 1, 32700 +point 210, 32700 +point 60, 16000 +hang + +.envelope envelope_6A0C +point 1, 32700 +point 100, 32700 +point 100, 10000 +hang + +.envelope envelope_6A1C +point 1, 32700 +point 250, 32700 +point 30, 16000 +hang + +.envelope envelope_6A2C +point 1, 32700 +point 650, 32700 +point 150, 16000 +hang + +.envelope envelope_6A3C +point 1, 32700 +point 500, 32700 +point 150, 16000 +hang + +.envelope envelope_6A4C +point 1, 32700 +point 500, 32700 +point 200, 26000 +hang + +.envelope envelope_6A5C +point 1, 32700 +point 800, 32700 +point 200, 16000 +hang + +.envelope envelope_unused_6A6C +point 1, 32700 +point 900, 32700 +point 200, 30000 +hang + +.envelope envelope_6A7C +point 1, 32700 +hang diff --git a/assets/sequences/001_Ambient_Effects.prg.seq b/assets/sequences/001_Ambient_Effects.prg.seq new file mode 100644 index 00000000000..e0dc7d8977e --- /dev/null +++ b/assets/sequences/001_Ambient_Effects.prg.seq @@ -0,0 +1,2092 @@ +.desc title "Ambient Effects" +.desc type "program" +.usefont SOUNDFONT_AMBIENCE + +.sequence sequence_start +mutebhv 0x20 +mutescale 70 +vol 115 +tempo 120 +ldio 0 +bgez seq_D +end +.sequence seq_D +ldio 4 +stseq 32, seq_17+1 +ldio 5 +stseq 0, seq_17+2 +.sequence seq_17 +initchan 0xD000 +ldchan 13, chan_EDB +ldio 5 +and 1 +rbeqz seq_25 +ldchan 0, chan_2AA +.sequence seq_25 +ldio 5 +and 2 +rbeqz seq_2D +ldchan 1, chan_91 +.sequence seq_2D +ldio 5 +and 4 +rbeqz seq_35 +ldchan 2, chan_91 +.sequence seq_35 +ldio 5 +and 8 +rbeqz seq_3D +ldchan 3, chan_91 +.sequence seq_3D +ldio 5 +and 16 +rbeqz seq_45 +ldchan 4, chan_91 +.sequence seq_45 +ldio 5 +and 32 +rbeqz seq_4D +ldchan 5, chan_91 +.sequence seq_4D +ldio 5 +and 64 +rbeqz seq_55 +ldchan 6, chan_91 +.sequence seq_55 +ldio 5 +and 128 +rbeqz seq_5D +ldchan 7, chan_91 +.sequence seq_5D +ldio 4 +and 1 +rbeqz seq_65 +ldchan 8, chan_91 +.sequence seq_65 +ldio 4 +and 2 +rbeqz seq_6A +.sequence seq_6A +ldio 4 +and 4 +rbeqz seq_6F +.sequence seq_6F +ldio 4 +and 8 +rbeqz seq_74 +.sequence seq_74 +ldio 4 +and 16 +rbeqz seq_7C +ldchan 12, chan_2AA +.sequence seq_7C +ldio 4 +and 64 +rbeqz seq_84 +ldchan 14, chan_DA3 +.sequence seq_84 +ldio 4 +and 128 +rbeqz seq_8C +ldchan 15, chan_E0B +.sequence seq_8C +delay 0x7FD0 +rjump seq_8C + +.channel chan_91 +noshort +rvrbidx 1 +ldfilter filter_1030 +filter 0 +.channel chan_99 +delay1 +panweight 0 +ldio 1 +sub 1 +rbeqz chan_A3 +rjump chan_99 +.channel chan_A3 +ldio 2 +sub 18 +rbltz chan_AB +ldi 17 +stio 2 +.channel chan_AB +ldio 2 +ldseq addr_16B +stseq 0, chan_D7+1 +ldio 2 +ldseq addr_17F +stseq 0, chan_D9+1 +ldio 2 +ldseqtoptr addr_192 +stptrtoseq chan_DE+1 +ldio 2 +ldseqtoptr addr_1BA +stptrtoseq chan_E5+1 +ldio 2 +ldseqtoptr addr_1E2 +stptrtoseq chan_EC+1 +ldio 2 +ldseqtoptr addr_20A +stptrtoseq chan_F3+1 +.channel chan_D7 +instr FONT02_INSTR_BIRD_CHIRP_0 +.channel chan_D9 +vol 60 +ldio 4 +and 3 +.channel chan_DE +ldlayer 0, layer_393 +rbeqz chan_F9 +sub 1 +.channel chan_E5 +ldlayer 1, layer_3CE +rbeqz chan_F9 +sub 1 +.channel chan_EC +ldlayer 2, layer_38C +rbeqz chan_F9 +sub 1 +.channel chan_F3 +ldlayer 3, layer_3C4 +ldi 1 +stio 7 +.channel chan_F9 +delay1 +ldio 5 +and 63 +stio 5 +ldseq addr_F7A +stseq 10, chan_10E+1 +ldi 127 +subio 5 +stseq 0, @+1 +volexp 127 +.channel chan_10E +reverb 0 +ldio 1 +sub 0 +rbeqz chan_164 +ldio 7 +sub 1 +stio 7 +rbeqz chan_11D +rjump chan_F9 +.channel chan_11D +ldio 2 +ldseqtoptr addr_232 +stptrtoseq chan_134+2 +ldio 2 +ldseqtoptr addr_25A +stptrtoseq chan_146+2 +ldio 2 +ldseqtoptr addr_282 +stptrtoseq chan_15B+2 +rand 90 +.channel chan_134 +stseq 37, layer_fn_EFC+1 +ldio 3 +and 127 +stio 3 +ldi 0 +subio 3 +stseq 0, chan_144+1 +ldio 3 +.channel chan_144 +bendfine 0 +.channel chan_146 +stseq 0, layer_EFE+1 +ldi 0 +ldseq addr_EFB +rbeqz chan_15B +rand 3 +rbeqz chan_159 +ldi 0 +rjump chan_15B +.channel chan_159 +ldi 20 +.channel chan_15B +stseq 0, layer_F00+1 +ldi 50 +stio 7 +rjump chan_F9 +.channel chan_164 +dellayer 0 +dellayer 1 +dellayer 2 +dellayer 3 +jump chan_99 + +.array addr_16B +byte FONT02_INSTR_BIRD_CHIRP_0 +byte FONT02_INSTR_INSECTS +byte FONT02_INSTR_BIRD_CHIRP_1 +byte FONT02_INSTR_BIRD_CHIRP_0 +byte FONT02_INSTR_CRICKETS +byte FONT02_INSTR_BIRD_CHIRP_0 +byte FONT02_INSTR_BIRD_CHIRP_2 +byte FONT02_INSTR_BIRD_CHIRP_0 +byte FONT02_INSTR_BIRD_CHIRP_0 +byte FONT02_INSTR_CROWS +byte FONT02_INSTR_BIRD_CHIRP_3 +byte FONT02_INSTR_BIRD_SCREECH +byte FONT02_INSTR_BIRD_SONG +byte FONT02_INSTR_OWL +byte FONT02_INSTR_HAWK +byte FONT02_INSTR_BIRD_CALL +byte FONT02_INSTR_BIRD_CAW +byte FONT02_INSTR_CUCCO +byte FONT02_INSTR_BIRD_CHIRP_1 +byte FONT02_INSTR_BIRD_CHIRP_0 + +.array addr_17F +byte 0x4B +byte 0x55 +byte 0x32 +byte 0x3C +byte 0x50 +byte 0x50 +byte 0x50 +byte 0x50 +byte 0x50 +byte 0x64 +byte 0x50 +byte 0x50 +byte 0x50 +byte 0x52 +byte 0x50 +byte 0x4B +byte 0x5A +byte 0x50 +byte 0x0 + +.table addr_192 +entry layer_393 +entry layer_404 +entry layer_48A +entry layer_4D1 +entry layer_54E +entry layer_5B2 +entry layer_665 +entry layer_6CE +entry layer_734 +entry layer_78B +entry layer_7E6 +entry layer_B39 +entry layer_C5E +entry layer_9C2 +entry layer_A6C +entry layer_D39 +entry layer_8A2 +entry layer_AE6 +entry layer_48A +entry layer_4D1 + +.table addr_1BA +entry layer_3CE +entry layer_449 +entry layer_487 +entry layer_516 +entry layer_560 +entry layer_612 +entry layer_676 +entry layer_6E8 +entry layer_731 +entry layer_794 +entry layer_849 +entry layer_BC9 +entry layer_CCD +entry layer_A09 +entry layer_A59 +entry layer_D27 +entry layer_932 +entry layer_AFA +entry layer_A59 +entry layer_D27 + +.table addr_1E2 +entry layer_38C +entry layer_3FD +entry layer_484 +entry layer_4C7 +entry layer_572 +entry layer_5AC +entry layer_68B +entry layer_6FA +entry layer_74E +entry layer_7B2 +entry layer_7E0 +entry layer_B26 +entry layer_C4D +entry layer_9B8 +entry layer_A62 +entry layer_D2A +entry layer_898 +entry layer_AE5 +entry layer_A62 +entry layer_D2A + +.table addr_20A +entry layer_3C4 +entry layer_43F +entry layer_481 +entry layer_50C +entry layer_58D +entry layer_609 +entry layer_6B4 +entry layer_716 +entry layer_770 +entry layer_7C9 +entry layer_843 +entry layer_BB3 +entry layer_CB9 +entry layer_9FC +entry layer_A4C +entry layer_D24 +entry layer_924 +entry layer_AE5 +entry layer_A4C +entry layer_D24 + +.table addr_232 +entry layer_fn_EFC+1 +entry layer_fn_F03+1 +entry layer_fn_F0A+1 +entry layer_fn_F11+1 +entry layer_fn_F18+1 +entry layer_fn_F1F+1 +entry layer_fn_F26+1 +entry layer_fn_F2D+1 +entry layer_fn_F34+1 +entry layer_fn_F3B+1 +entry layer_fn_F42+1 +entry layer_fn_F49+1 +entry layer_fn_F50+1 +entry layer_fn_F57+1 +entry layer_fn_F5E+1 +entry layer_fn_F65+1 +entry layer_fn_F6C+1 +entry layer_fn_F73+1 +entry layer_fn_F0A+1 +entry layer_fn_F11+1 + +.table addr_25A +entry layer_EFE+1 +entry layer_F05+1 +entry layer_F0C+1 +entry layer_F13+1 +entry layer_F1A+1 +entry layer_F21+1 +entry layer_F28+1 +entry layer_F2F+1 +entry layer_F36+1 +entry layer_F3D+1 +entry layer_F44+1 +entry layer_F4B+1 +entry layer_F52+1 +entry layer_F59+1 +entry layer_F60+1 +entry layer_F67+1 +entry layer_F6E+1 +entry layer_F75+1 +entry layer_F60+1 +entry layer_F67+1 + +.table addr_282 +entry layer_F00+1 +entry layer_F07+1 +entry layer_F0E+1 +entry layer_F15+1 +entry layer_F1C+1 +entry layer_F23+1 +entry layer_F2A+1 +entry layer_F31+1 +entry layer_F38+1 +entry layer_F3F+1 +entry layer_F46+1 +entry layer_F4D+1 +entry layer_F54+1 +entry layer_F5B+1 +entry layer_F62+1 +entry layer_F69+1 +entry layer_F70+1 +entry layer_F77+1 +entry layer_F62+1 +entry layer_F69+1 + +.channel chan_2AA +noshort +rvrbidx 1 +transpose 12 +ldfilter filter_1030 +filter 0 +.channel chan_2B4 +delay1 +ldio 1 +sub 1 +rbeqz chan_2BC +rjump chan_2B4 +.channel chan_2BC +volexp 127 +panweight 0 +ldio 2 +and 3 +ldseq addr_35A +stseq 0, chan_2D6+1 +ldio 2 +and 3 +ldseq addr_35E +stseq 0, @+1 +vol 60 +.channel chan_2D6 +instr FONT02_INSTR_WIND_HOWL +env envelope_FFA +reverb 20 +ldlayer 0, layer_368 +ldlayer 1, layer_362 +ldi 1 +stio 7 +rjump chan_2F4 +.channel chan_2E8 +delay1 +ldio 1 +sub 0 +rbeqz chan_335 +ldio 0 +rbltz chan_2F4 +call chan_fn_33E +.channel chan_2F4 +ldio 6 +rbltz chan_300 +stseq 0, chan_2FE+1 +ldi 255 +stio 6 +.channel chan_2FE +filter 15 +.channel chan_300 +ldio 7 +sub 1 +stio 7 +rbeqz chan_308 +rjump chan_2E8 +.channel chan_308 +ldio 3 +and 63 +stio 3 +ldseq addr_FBA +sub 255 +stseq 5, chan_31D+1 +ldio 3 +ldseq addr_F7A +stseq 96, envelope_FFE+2 +.channel chan_31D +rand 24 +stseq 98, layer_36F +ldi 64 +subio 3 +stseq 0, @+1 +rand 64 +stseq 63, layer_36F+1 +ldi 100 +stio 7 +rjump chan_2E8 +.channel chan_335 +releaserate 112 +dellayer 0 +dellayer 1 +dellayer 2 +dellayer 3 +jump chan_2B4 + +.channel chan_fn_33E +ldlayer 2, layer_37A +ldlayer 3, layer_374 +ldio 3 +and 63 +stio 3 +ldseq addr_FBA +sub 255 +stseq 100, layer_385+2 +stseq 100, layer_388+2 +stseq 103, layer_385 +end + +.array addr_35A +byte 0xF +byte 0x10 +byte 0x11 +byte 0x11 + +.array addr_35E +byte 0x3C +byte 0x73 +byte 0x64 +byte 0x64 + +.layer layer_362 +stereo 20 +transpose 9 +rjump layer_368 + +.layer layer_368 +releaserate 100 +legato +portamento 0x85, 34, 255 +.layer layer_36F +notedv PITCH_C3, 0x64, 75 +rjump layer_36F + +.layer layer_374 +transpose 9 +notepan 74 +rjump layer_37C + +.layer layer_37A +notepan 54 +.layer layer_37C +env envelope_1006, 255 +legato +portamento 0x85, 39, 255 +.layer layer_385 +notedv PITCH_G4, 0xC, 40 +.layer layer_388 +notedv PITCH_G2, 0x73, 40 +end + +.layer layer_38C +notepan 94 +call layer_fn_EFC +rjump layer_395 + +.layer layer_393 +notepan 84 +.layer layer_395 +call layer_fn_EFC +notedv PITCH_E4, 0x7E, 100 +notedv PITCH_D4, 0x15F, 78 +call layer_fn_EFC +notedv PITCH_D4, 0xE2, 95 +notedv PITCH_C4, 0x2D, 86 +notedv PITCH_F4, 0x144, 75 +notedv PITCH_D4, 0xC4, 97 +call layer_fn_EFC +notedv PITCH_D4, 0xD3, 67 +notedv PITCH_E4, 0x3B, 106 +notedv PITCH_C4, 0x10B, 94 +call layer_fn_EFC +rjump layer_395 + +.layer layer_3C4 +notepan 34 +call layer_fn_EFC +call layer_fn_EFC +rjump layer_395 + +.layer layer_3CE +notepan 44 +.layer layer_3D0 +call layer_fn_EFC +call layer_fn_EFC +notedv PITCH_C4, 0x9, 64 +notedv PITCH_C4, 0x96, 75 +call layer_fn_EFC +notedv PITCH_C4, 0x5F, 100 +notedv PITCH_C4, 0x137, 90 +notedv PITCH_C4, 0xCE, 75 +call layer_fn_EFC +notedv PITCH_C4, 0x119, 86 +notedv PITCH_C4, 0x23, 69 +notedv PITCH_C4, 0x54, 77 +notedv PITCH_C4, 0x65, 81 +rjump layer_3D0 + +.layer layer_3FD +notepan 84 +call layer_fn_F03 +rjump layer_406 + +.layer layer_404 +notepan 94 +.layer layer_406 +call layer_fn_F03 +notedv PITCH_D4, 0xC, 81 +notedv PITCH_E4, 0xFE, 99 +notedv PITCH_D4, 0x34, 89 +call layer_fn_F03 +notedv PITCH_C4, 0xF4, 86 +notedv PITCH_D4, 0x187, 97 +call layer_fn_F03 +notedv PITCH_C4, 0x15, 72 +notedv PITCH_D4, 0xD3, 67 +notedv PITCH_E4, 0x91, 98 +call layer_fn_F03 +notedv PITCH_E4, 0x8, 86 +notedv PITCH_D4, 0x13B, 94 +notedv PITCH_C4, 0xB, 94 +notedv PITCH_C4, 0x10F, 94 +rjump layer_406 + +.layer layer_43F +notepan 44 +call layer_fn_F03 +call layer_fn_F03 +rjump layer_44B + +.layer layer_449 +notepan 34 +.layer layer_44B +call layer_fn_F03 +call layer_fn_F03 +notedv PITCH_C4, 0xD3, 72 +call layer_fn_F03 +notedv PITCH_C4, 0xB, 85 +notedv PITCH_E4, 0x126, 100 +notedv PITCH_D4, 0xA7, 90 +call layer_fn_F03 +notedv PITCH_D4, 0xA6, 75 +notedv PITCH_F4, 0x18, 86 +notedv PITCH_C4, 0x163, 84 +call layer_fn_F03 +notedv PITCH_D4, 0xDB, 94 +notedv PITCH_E4, 0x9, 67 +notedv PITCH_C4, 0xE0, 81 +rjump layer_44B + +.layer layer_481 +call layer_fn_F0A + +.layer layer_484 +call layer_fn_F0A + +.layer layer_487 +call layer_fn_F0A + +.layer layer_48A +call layer_fn_F0A +notepan 64 +notedvg PITCH_C4, 0x200, 90, 127 +call layer_fn_F0A +notepan 91 +notedvg PITCH_D4, 0x7F, 61, 127 +ldelay 0x96 +notepan 77 +notedvg PITCH_DF4, 0x1C8, 100, 127 +call layer_fn_F0A +notepan 38 +notedvg PITCH_C4, 0x174, 54, 127 +ldelay 0xAE +notepan 87 +notedvg PITCH_DF4, 0x298, 73, 127 +call layer_fn_F0A +notepan 54 +notedvg PITCH_C4, 0x1B5, 95, 127 +rjump layer_48A + +.layer layer_4C7 +notepan 74 +call layer_fn_F11 +call layer_fn_F11 +rjump layer_4D3 + +.layer layer_4D1 +notepan 94 +.layer layer_4D3 +call layer_fn_F11 +call layer_fn_F11 +notedv PITCH_E4, 0x108, 100 +notedv PITCH_D4, 0xB, 78 +notedv PITCH_D4, 0x2D, 95 +call layer_fn_F11 +notedv PITCH_C4, 0xF6, 86 +notedv PITCH_D4, 0x155, 97 +call layer_fn_F11 +notedv PITCH_D4, 0xD3, 67 +notedv PITCH_C4, 0x15, 94 +notedv PITCH_E4, 0x91, 106 +call layer_fn_F11 +notedv PITCH_D4, 0x13B, 94 +notedv PITCH_E4, 0x8, 106 +notedv PITCH_C4, 0x10F, 94 +rjump layer_4D3 + +.layer layer_50C +notepan 54 +call layer_fn_F11 +call layer_fn_F11 +rjump layer_518 + +.layer layer_516 +notepan 34 +.layer layer_518 +call layer_fn_F11 +call layer_fn_F11 +notedv PITCH_C4, 0xFA, 64 +call layer_fn_F11 +notedv PITCH_C4, 0xE, 75 +notedv PITCH_E4, 0x10F, 100 +notedv PITCH_D4, 0x8, 90 +call layer_fn_F11 +notedv PITCH_D4, 0x92, 75 +notedv PITCH_F4, 0x43, 86 +notedv PITCH_C4, 0x155, 69 +call layer_fn_F11 +notedv PITCH_D4, 0xF5, 77 +notedv PITCH_E4, 0xBD, 77 +notedv PITCH_C4, 0xDA, 81 +rjump layer_518 + +.layer layer_54E +call layer_fn_F18 +notepan 84 +notedv PITCH_E4, 0x126, 100 +notepan 74 +notedv PITCH_E4, 0x9, 78 +notedv PITCH_C4, 0x16F, 74 + +.layer layer_560 +call layer_fn_F18 +call layer_fn_F18 +notepan 47 +notedv PITCH_C4, 0x1C2, 100 +notepan 58 +notedv PITCH_D4, 0xF8, 91 + +.layer layer_572 +call layer_fn_F18 +ldelay 0x14 +call layer_fn_F18 +notepan 95 +notedv PITCH_F4, 0x4B, 67 +notepan 87 +notedv PITCH_D4, 0x9, 55 +notedv PITCH_D4, 0x18, 60 +notepan 91 +notedv PITCH_E4, 0x126, 100 + +.layer layer_58D +call layer_fn_F18 +call layer_fn_F18 +ldelay 0x30 +call layer_fn_F18 +notepan 72 +notedv PITCH_C4, 0xA, 91 +notedv PITCH_DF4, 0xC2, 88 +notepan 37 +notedv PITCH_D4, 0x9, 76 +notedv PITCH_D4, 0x155, 91 +rjump layer_54E + +.layer layer_5AC +call layer_fn_F1F +call layer_fn_F1F + +.layer layer_5B2 +call layer_fn_F1F +notepan 84 +call layer_fn_F1F +notedv PITCH_D4, 0xC2, 90 +notedv PITCH_EF4, 0x68, 94 +call layer_fn_F1F +notedv PITCH_D4, 0x95, 100 +notedv PITCH_E4, 0x61, 105 +call layer_fn_F1F +notedv PITCH_D4, 0x126, 78 +call layer_fn_F1F +notedv PITCH_C4, 0x6, 84 +notedv PITCH_E4, 0x24, 76 +notedv PITCH_C4, 0x19D, 78 +notedv PITCH_C4, 0x5E, 57 +notepan 74 +call layer_fn_F1F +notedv PITCH_D4, 0xA8, 88 +notedv PITCH_C4, 0x159, 67 +notedv PITCH_E4, 0x105, 84 +notedv PITCH_E4, 0x43, 67 +call layer_fn_F1F +notedv PITCH_DF4, 0xD3, 81 +call layer_fn_F1F +notedv PITCH_D4, 0xB, 91 +notedv PITCH_E4, 0x126, 88 +rjump layer_5B2 + +.layer layer_609 +call layer_fn_F1F +call layer_fn_F1F +call layer_fn_F1F + +.layer layer_612 +call layer_fn_F1F +notepan 44 +notedv PITCH_D4, 0x15, 75 +notedv PITCH_EF4, 0x3D, 94 +call layer_fn_F1F +notedv PITCH_D4, 0x95, 81 +notedv PITCH_E4, 0x137, 42 +notedv PITCH_C4, 0x1F4, 69 +call layer_fn_F1F +notedv PITCH_F4, 0xC8, 91 +notedv PITCH_D4, 0x95, 84 +notepan 54 +call layer_fn_F1F +notedv PITCH_EF4, 0x95, 87 +notedv PITCH_D4, 0x163, 96 +call layer_fn_F1F +notedv PITCH_EF4, 0xD8, 61 +call layer_fn_F1F +notedv PITCH_C4, 0x1E0, 81 +noteldv 39, 0x4F, 68 +call layer_fn_F1F +notedv PITCH_E4, 0x8, 75 +notedv PITCH_EF4, 0x1A5, 94 +call layer_fn_F1F +rjump layer_612 + +.layer layer_665 +loop 3 +notepan 104 +notedv PITCH_E4, 0x1CC, 75 +call layer_fn_F26 +notepan 50 +notedv PITCH_C4, 0x167, 87 + +.layer layer_676 +call layer_fn_F26 +call layer_fn_F26 +notepan 34 +notedv PITCH_D4, 0x167, 94 +call layer_fn_F26 +notepan 64 +notedv PITCH_D4, 0x167, 62 + +.layer layer_68B +call layer_fn_F26 +ldelay 0x22 +call layer_fn_F26 +notepan 79 +notedv PITCH_E4, 0x167, 79 +call layer_fn_F26 +notepan 91 +notedv PITCH_F4, 0x167, 62 +call layer_fn_F26 +notepan 54 +notedv PITCH_C4, 0x167, 86 +call layer_fn_F26 +notepan 36 +notedv PITCH_D4, 0x167, 57 + +.layer layer_6B4 +call layer_fn_F26 +call layer_fn_F26 +ldelay 0x37 +call layer_fn_F26 +loopend +notepan 64 +notedv PITCH_C4, 0x9, 57 +notedv PITCH_E4, 0xD8, 69 +call layer_fn_F26 +rjump layer_665 + +.layer layer_6CE +call layer_fn_F2D +notepan 74 +notedv PITCH_E4, 0x15F, 86 +call layer_fn_F2D +notedv PITCH_E4, 0x126, 59 +notepan 90 +notedv PITCH_E4, 0x15F, 66 +notedv PITCH_C4, 0x126, 49 + +.layer layer_6E8 +call layer_fn_F2D +ldelay 0x47 +call layer_fn_F2D +notedv PITCH_D4, 0x137, 81 +notepan 83 +notedv PITCH_E4, 0x10B, 99 + +.layer layer_6FA +call layer_fn_F2D +call layer_fn_F2D +ldelay 0x21 +call layer_fn_F2D +notedv PITCH_C4, 0x18D, 49 +notedv PITCH_C4, 0x116, 78 +notepan 69 +call layer_fn_F2D +notedv PITCH_C4, 0x1C4, 57 + +.layer layer_716 +call layer_fn_F2D +call layer_fn_F2D +call layer_fn_F2D +call layer_fn_F2D +notedv PITCH_C4, 0x149, 92 +notepan 78 +notedv PITCH_C4, 0x108, 75 +call layer_fn_F2D +rjump layer_6CE + +.layer layer_731 +call layer_fn_F34 + +.layer layer_734 +notepan 54 +call layer_fn_F34 +notepan 49 +notedv PITCH_E4, 0xBF, 86 +notepan 41 +notedv PITCH_D4, 0x44, 59 +notedv PITCH_C4, 0x1CA, 91 +notepan 57 +notedv PITCH_C4, 0xEE, 77 + +.layer layer_74E +call layer_fn_F34 +call layer_fn_F34 +ldelay 0x19 +notepan 39 +notedv PITCH_E4, 0xC2, 59 +notedv PITCH_D4, 0xA4, 49 +notepan 51 +notedv PITCH_D4, 0x13F, 55 +notepan 59 +notedv PITCH_C4, 0xDB, 72 +notedv PITCH_C4, 0x2F9, 86 + +.layer layer_770 +call layer_fn_F34 +call layer_fn_F34 +call layer_fn_F34 +ldelay 0x4B +notepan 48 +notedv PITCH_D4, 0x34, 95 +notepan 53 +notedv PITCH_C4, 0xED, 64 +call layer_fn_F34 +rjump layer_734 + +.layer layer_78B +call layer_fn_F3B +notedv PITCH_C4, 0x4F, 95 +notedv PITCH_C4, 0x4F, 95 + +.layer layer_794 +call layer_fn_F3B +call layer_fn_F3B +notedv PITCH_C4, 0xA9, 75 +notedv PITCH_C4, 0x63, 73 +notedv PITCH_C4, 0x91, 71 +call layer_fn_F3B +notedv PITCH_C4, 0x55, 78 +notedv PITCH_C4, 0xD3, 74 +call layer_fn_F3B + +.layer layer_7B2 +call layer_fn_F3B +ldelay 0x29 +call layer_fn_F3B +notedv PITCH_C4, 0x45, 57 +notedv PITCH_C4, 0x5E, 57 +call layer_fn_F3B +notedv PITCH_C4, 0x4B, 49 +notedv PITCH_C4, 0x48, 46 + +.layer layer_7C9 +call layer_fn_F3B +ldelay 0x44 +call layer_fn_F3B +call layer_fn_F3B +notedv PITCH_C4, 0x54, 88 +notedv PITCH_C4, 0x5B, 88 +notedv PITCH_C4, 0xBF, 83 +rjump layer_78B + +.layer layer_7E0 +call layer_fn_F42 +call layer_fn_F42 + +.layer layer_7E6 +call layer_fn_F42 +notepan 24 +notedvg PITCH_E4, 0x1AA, 86, 127 +notedvg PITCH_D4, 0x73, 56, 127 +call layer_fn_F42 +notepan 49 +notedvg PITCH_C4, 0x1F4, 94, 127 +call layer_fn_F42 +notedvg PITCH_E4, 0x349, 68, 127 +notedvg PITCH_F4, 0x167, 71, 127 +call layer_fn_F42 +notedvg PITCH_E4, 0x349, 68, 127 +notedvg PITCH_E4, 0x229, 91, 127 +notedvg PITCH_F4, 0xDB, 71, 127 +call layer_fn_F42 +notedvg PITCH_F4, 0x12C, 82, 220 +call layer_fn_F42 +notedvg PITCH_E4, 0x282, 81, 127 +notedvg PITCH_E4, 0x4F, 68, 127 +notedvg PITCH_F4, 0xDB, 71, 127 +call layer_fn_F42 +notedvg PITCH_F4, 0x1C3, 54, 127 +call layer_fn_F42 +rjump layer_7E6 + +.layer layer_843 +call layer_fn_F42 +call layer_fn_F42 + +.layer layer_849 +call layer_fn_F42 +call layer_fn_F42 +notepan 76 +call layer_fn_F42 +notedvg PITCH_E4, 0x142, 86, 127 +call layer_fn_F42 +notedvg PITCH_D4, 0x1F4, 94, 127 +call layer_fn_F42 +notedvg PITCH_E4, 0xFE, 49, 127 +notedvg PITCH_C4, 0xC3, 71, 127 +notedvg PITCH_D4, 0x1CB, 61, 127 +call layer_fn_F42 +notedvg PITCH_D4, 0x25, 51, 127 +call layer_fn_F42 +notedvg PITCH_DF4, 0x23D, 91, 127 +notedvg PITCH_C4, 0x2FD, 88, 127 +notepan 100 +call layer_fn_F42 +notedvg PITCH_E4, 0x15C, 76, 127 +notedvg PITCH_F4, 0x284, 59, 180 +rjump layer_849 + +.layer layer_898 +notepan 84 +call layer_fn_EFC +call layer_fn_EFC +rjump layer_8A4 + +.layer layer_8A2 +notepan 60 +.layer layer_8A4 +call layer_fn_EFC +notedv PITCH_C3, 0x34, 89 +call layer_fn_F6C +call layer_fn_F6C +call layer_fn_F6C +notedv PITCH_C3, 0x34, 77 +notedv PITCH_C3, 0x34, 77 +call layer_fn_F6C +call layer_fn_F6C +call layer_fn_F6C +call layer_fn_F6C +notedv PITCH_C3, 0x34, 71 +notedv PITCH_C3, 0x34, 71 +call layer_fn_F6C +call layer_fn_F6C +call layer_fn_F6C +notedv PITCH_C3, 0x34, 76 +call layer_fn_F6C +call layer_fn_F6C +call layer_fn_F6C +notedv PITCH_C3, 0x34, 89 +call layer_fn_F6C +call layer_fn_F6C +call layer_fn_F6C +notedv PITCH_C3, 0x34, 64 +notedv PITCH_C3, 0x34, 66 +notedv PITCH_C3, 0x34, 69 +call layer_fn_F6C +call layer_fn_F6C +notedv PITCH_C3, 0x34, 75 +call layer_fn_F6C +call layer_fn_F6C +call layer_fn_F6C +call layer_fn_F6C +notedv PITCH_C3, 0x34, 85 +call layer_fn_F6C +call layer_fn_F6C +notedv PITCH_C3, 0x34, 79 +notedv PITCH_C3, 0x34, 77 +notedv PITCH_C3, 0x34, 71 +call layer_fn_F6C +call layer_fn_F6C +rjump layer_8A4 + +.layer layer_924 +notepan 42 +call layer_fn_EFC +call layer_fn_EFC +call layer_fn_EFC +jump layer_934 + +.layer layer_932 +notepan 69 +.layer layer_934 +call layer_fn_EFC +notedv PITCH_C3, 0x30, 45 +notedv PITCH_C3, 0x32, 48 +notedv PITCH_C3, 0x34, 47 +call layer_fn_F6C +call layer_fn_F6C +call layer_fn_F6C +notedv PITCH_C3, 0x34, 80 +notedv PITCH_C3, 0x34, 81 +call layer_fn_F6C +call layer_fn_F6C +call layer_fn_F6C +notedv PITCH_C3, 0x32, 88 +notedv PITCH_C3, 0x34, 84 +call layer_fn_F6C +call layer_fn_F6C +call layer_fn_F6C +notedv PITCH_C3, 0x32, 94 +call layer_fn_F6C +call layer_fn_F6C +call layer_fn_F6C +notedv PITCH_C3, 0x32, 76 +call layer_fn_F6C +notedv PITCH_C3, 0x32, 55 +call layer_fn_F6C +notedv PITCH_C3, 0x32, 65 +call layer_fn_F6C +call layer_fn_F6C +call layer_fn_F6C +call layer_fn_F6C +call layer_fn_F6C +notedv PITCH_C3, 0x36, 83 +notedv PITCH_C3, 0x34, 87 +call layer_fn_F6C +call layer_fn_F6C +notedv PITCH_C3, 0x36, 91 +notedv PITCH_C3, 0x34, 85 +call layer_fn_F6C +call layer_fn_F6C +call layer_fn_F6C +notedv PITCH_C3, 0x34, 65 +notedv PITCH_C3, 0x30, 59 +call layer_fn_F6C +jump layer_934 + +.layer layer_9B8 +notepan 40 +call layer_fn_F57 +call layer_fn_F57 +rjump layer_A11 + +.layer layer_9C2 +notepan 50 +.layer layer_9C4 +call layer_fn_F57 +notedv PITCH_C4, 0x41, 86 +ldelay 0x9F +call layer_fn_F57 +notedv PITCH_DF4, 0x36, 56 +ldelay 0x123 +call layer_fn_F57 +notedv PITCH_C4, 0x45, 36 +ldelay 0x95 +call layer_fn_F57 +notedv PITCH_D4, 0x32, 70 +ldelay 0xE2 +call layer_fn_F57 +notedv PITCH_C4, 0x4C, 51 +ldelay 0x8F +notedv PITCH_D4, 0x3D, 70 +ldelay 0x14E +call layer_fn_F57 +rjump layer_9C4 + +.layer layer_9FC +notepan 88 +call layer_fn_F57 +call layer_fn_F57 +call layer_fn_F57 +rjump layer_A11 + +.layer layer_A09 +call layer_fn_F57 +notepan 78 +ldelay 0xD3 +.layer layer_A11 +call layer_fn_F57 +ldelay 0x1BB +call layer_fn_F57 +ldelay 0x108 +call layer_fn_F57 +notedv PITCH_C4, 0x47, 44 +ldelay 0x1A3 +call layer_fn_F57 +notedv PITCH_C4, 0x47, 64 +call layer_fn_F57 +notedv PITCH_DF4, 0x38, 71 +ldelay 0x15F +call layer_fn_F57 +notedv PITCH_D4, 0x3C, 89 +ldelay 0x2C1 +call layer_fn_F57 +notedv PITCH_C4, 0x39, 57 +ldelay 0x160 +call layer_fn_F57 +rjump layer_A11 + +.layer layer_A4C +notepan 78 +call layer_fn_F5E +call layer_fn_F5E +call layer_fn_F5E +rjump layer_AAA + +.layer layer_A59 +notepan 70 +call layer_fn_F5E +ldelay 0x38 +rjump layer_AAA + +.layer layer_A62 +notepan 40 +call layer_fn_F5E +call layer_fn_F5E +rjump layer_A6E + +.layer layer_A6C +notepan 50 +.layer layer_A6E +call layer_fn_F57 +notedv PITCH_E3, 0x61, 75 +notedv PITCH_E3, 0x5E, 79 +notedv PITCH_E3, 0x5F, 77 +call layer_fn_F5E +call layer_fn_F5E +call layer_fn_F5E +call layer_fn_F5E +notedv PITCH_F3, 0x69, 78 +notedv PITCH_F3, 0x70, 79 +notedv PITCH_F3, 0x6B, 72 +call layer_fn_F5E +call layer_fn_F5E +call layer_fn_F5E +notedv PITCH_E3, 0x5F, 69 +notedv PITCH_E3, 0x59, 74 +call layer_fn_F5E +call layer_fn_F5E +call layer_fn_F5E +call layer_fn_F5E +.layer layer_AAA +notedv PITCH_E3, 0x58, 81 +notedv PITCH_E3, 0x5D, 83 +notedv PITCH_E3, 0x5B, 77 +call layer_fn_F5E +call layer_fn_F5E +notedv PITCH_E3, 0x66, 69 +notedv PITCH_E3, 0x64, 74 +call layer_fn_F5E +call layer_fn_F5E +call layer_fn_F5E +call layer_fn_F5E +notedv PITCH_F3, 0x66, 74 +call layer_fn_F5E +call layer_fn_F5E +call layer_fn_F5E +notedv PITCH_E3, 0x4E, 87 +notedv PITCH_E3, 0x51, 78 +call layer_fn_F5E +call layer_fn_F5E +rjump layer_A6E + +.layer layer_AE5 +end + +.layer layer_AE6 +call layer_fn_F73 +notedv PITCH_C4, 0xA6, 75 +call layer_fn_F73 +call layer_fn_F73 +call layer_fn_F73 +notedv PITCH_DF4, 0xA6, 79 + +.layer layer_AFA +call layer_fn_F73 +call layer_fn_F73 +call layer_fn_F73 +call layer_fn_F73 +notedv PITCH_DF4, 0xA6, 84 +call layer_fn_F73 +call layer_fn_F73 +call layer_fn_F73 +notedv PITCH_C4, 0xA6, 102 +call layer_fn_F73 +call layer_fn_F73 +call layer_fn_F73 +notedv PITCH_C4, 0xA6, 64 +rjump layer_AE6 + +.layer layer_B26 +releaserate 236 +legato +notepan 34 +notedv PITCH_C4, 0x2A, 85 +call layer_fn_F49 +call layer_fn_F49 +call layer_fn_F49 +rjump layer_B3F + +.layer layer_B39 +releaserate 236 +call layer_fn_F49 +legato +.layer layer_B3F +notepan 95 +portamento 0x85, 38, 255 +notedv PITCH_DF4, 0x34, 76 +notedv PITCH_C4, 0x4F, 76 +call layer_fn_F49 +call layer_fn_F49 +notepan 37 +portamento 0x81, 38, 127 +notedv PITCH_C4, 0xE1, 99 +call layer_fn_F49 +notepan 49 +notedv PITCH_C4, 0x1A, 81 +call layer_fn_F49 +notepan 39 +portamento 0x81, 38, 127 +notedv PITCH_C4, 0x112, 91 +call layer_fn_F49 +notepan 55 +portamento 0x85, 39, 255 +notedv PITCH_DF4, 0x112, 78 +notedv PITCH_DF4, 0x5E, 78 +call layer_fn_F49 +call layer_fn_F49 +notepan 74 +portamento 0x81, 38, 127 +notedv PITCH_C4, 0x16, 105 +call layer_fn_F49 +notepan 46 +portamento 0x81, 38, 127 +notedv PITCH_DF4, 0x24, 94 +call layer_fn_F49 +call layer_fn_F49 +call layer_fn_F49 +notepan 94 +portamento 0x85, 39, 255 +notedv PITCH_DF4, 0x112, 78 +notedv PITCH_DF4, 0x5E, 78 +rjump layer_B3F + +.layer layer_BB3 +releaserate 236 +legato +call layer_fn_F49 +call layer_fn_F49 +call layer_fn_F49 +call layer_fn_F49 +notepan 84 +notedv PITCH_DF4, 0x5E, 64 +rjump layer_BD2 + +.layer layer_BC9 +releaserate 236 +call layer_fn_F49 +call layer_fn_F49 +legato +.layer layer_BD2 +notepan 94 +portamento 0x81, 38, 127 +notedv PITCH_C4, 0x74, 100 +call layer_fn_F49 +call layer_fn_F49 +notepan 76 +portamento 0x85, 39, 255 +notedv PITCH_DF4, 0x43, 85 +notedv PITCH_B3, 0xF1, 85 +call layer_fn_F49 +call layer_fn_F49 +call layer_fn_F49 +notepan 57 +notedv PITCH_C4, 0x44, 78 +call layer_fn_F49 +notepan 94 +portamento 0x81, 38, 127 +notedv PITCH_DF4, 0x91, 78 +call layer_fn_F49 +notepan 38 +portamento 0x81, 38, 127 +notedv PITCH_DF4, 0x59, 96 +call layer_fn_F49 +notepan 94 +portamento 0x85, 38, 255 +notedv PITCH_C4, 0xC3, 99 +notedv PITCH_B3, 0x17, 99 +call layer_fn_F49 +call layer_fn_F49 +notepan 64 +notedv PITCH_B3, 0x11, 76 +call layer_fn_F49 +notepan 37 +notedv PITCH_B3, 0x13, 105 +call layer_fn_F49 +notepan 43 +portamento 0x81, 38, 127 +notedv PITCH_C4, 0x112, 91 +call layer_fn_F49 +call layer_fn_F49 +rjump layer_BD2 + +.layer layer_C4D +releaserate 236 +notepan 34 +ldelay 0x18 +call layer_fn_F50 +notedv PITCH_C4, 0x2A, 85 +call layer_fn_F50 +rjump layer_C60 + +.layer layer_C5E +releaserate 236 +.layer layer_C60 +call layer_fn_F50 +notepan 75 +notedv PITCH_C4, 0x34, 94 +call layer_fn_F50 +notepan 34 +notedv PITCH_C4, 0x9F, 67 +call layer_fn_F50 +call layer_fn_F50 +notepan 72 +notedv PITCH_C4, 0xC5, 79 +call layer_fn_F50 +notepan 41 +notedv PITCH_C4, 0x85, 68 +call layer_fn_F50 +notepan 49 +notedv PITCH_C4, 0xD3, 99 +call layer_fn_F50 +call layer_fn_F50 +notepan 68 +notedv PITCH_C4, 0x3B, 94 +call layer_fn_F50 +call layer_fn_F50 +call layer_fn_F50 +notepan 105 +notedv PITCH_C4, 0xC5, 81 +call layer_fn_F50 +notepan 76 +notedv PITCH_C4, 0x3B, 86 +call layer_fn_F50 +call layer_fn_F50 +rjump layer_C60 + +.layer layer_CB9 +releaserate 236 +notepan 34 +call layer_fn_F50 +ldelay 0x18 +notedv PITCH_C4, 0x5E, 77 +call layer_fn_F50 +call layer_fn_F50 +rjump layer_CD2 + +.layer layer_CCD +releaserate 236 +call layer_fn_F50 +.layer layer_CD2 +call layer_fn_F50 +notepan 75 +notedv PITCH_C4, 0x98, 94 +call layer_fn_F50 +notepan 34 +notedv PITCH_C4, 0xD2, 84 +call layer_fn_F50 +call layer_fn_F50 +notepan 59 +notedv PITCH_C4, 0xA8, 99 +call layer_fn_F50 +notepan 95 +notedv PITCH_C4, 0x25, 74 +call layer_fn_F50 +call layer_fn_F50 +notepan 81 +notedv PITCH_C4, 0x2C, 88 +call layer_fn_F50 +call layer_fn_F50 +notepan 64 +notedv PITCH_C4, 0x4E, 91 +call layer_fn_F50 +notepan 37 +notedv PITCH_C4, 0x9E, 68 +call layer_fn_F50 +notepan 45 +notedv PITCH_C4, 0x73, 78 +call layer_fn_F50 +rjump layer_CD2 + +.layer layer_D24 +call layer_fn_F65 + +.layer layer_D27 +call layer_fn_F65 + +.layer layer_D2A +notepan 34 +ldelay 0x18 +call layer_fn_F65 +notedv PITCH_C4, 0x2A, 85 +call layer_fn_F65 +rjump layer_D3C + +.layer layer_D39 +call layer_fn_F65 +.layer layer_D3C +notepan 75 +notedv PITCH_C4, 0x34, 94 +call layer_fn_F65 +call layer_fn_F65 +notepan 47 +notedv PITCH_DF4, 0x28, 76 +notedv PITCH_DF4, 0x2A, 77 +call layer_fn_F65 +call layer_fn_F65 +call layer_fn_F65 +call layer_fn_F65 +notepan 61 +notedv PITCH_C4, 0x24, 76 +call layer_fn_F65 +call layer_fn_F65 +call layer_fn_F65 +notepan 37 +notedv PITCH_C4, 0x2B, 65 +notedv PITCH_C4, 0x33, 65 +call layer_fn_F65 +call layer_fn_F65 +call layer_fn_F65 +notepan 87 +notedv PITCH_C4, 0x21, 88 +notedv PITCH_C4, 0x2F, 88 +call layer_fn_F65 +notepan 71 +notedv PITCH_C4, 0x2D, 77 +notedv PITCH_C4, 0x27, 77 +call layer_fn_F65 +call layer_fn_F65 +call layer_fn_F65 +notepan 49 +notedv PITCH_C4, 0x37, 85 +call layer_fn_F65 +call layer_fn_F65 +rjump layer_D3C + +.channel chan_DA3 +noshort +rvrbidx 1 +ldfilter filter_1030 +filter 0 +.channel chan_DAB +delay1 +ldio 1 +sub 1 +rbeqz chan_DB3 +rjump chan_DAB +.channel chan_DB3 +vol 80 +volexp 127 +panweight 0 +instr FONT02_INSTR_RAIN +env envelope_1012 +ldlayer 0, layer_DED +ldlayer 1, layer_DF9 +ldlayer 2, layer_DFF +.channel chan_DC7 +delay1 +ldio 4 +rbltz chan_DDF +and 63 +stseq 0, chan_DDD+1 +ldio 4 +and 63 +ldseq addr_F7A +stseq 80, @+1 +vol 96 +.channel chan_DDD +bend 0 +.channel chan_DDF +ldio 1 +sub 0 +rbeqz chan_DE6 +rjump chan_DC7 +.channel chan_DE6 +releaserate 92 +dellayer 0 +dellayer 1 +dellayer 2 +rjump chan_DAB + +.layer layer_DED +notepan 84 +.layer layer_DEF +legato +portamento 1, 34, 100 +.layer layer_DF4 +notedv PITCH_C4, 0x60, 100 +rjump layer_DF4 + +.layer layer_DF9 +transpose 1 +notepan 44 +rjump layer_DEF + +.layer layer_DFF +stereo 20 +legato +portamento 1, 34, 100 +.layer layer_E06 +notedv PITCH_BF3, 0x60, 100 +rjump layer_E06 + +.channel chan_E0B +noshort +rvrbidx 1 +ldfilter filter_1030 +filter 0 +.channel chan_E13 +delay1 +ldio 1 +sub 1 +rbeqz chan_E1B +rjump chan_E13 +.channel chan_E1B +vol 95 +volexp 127 +panweight 0 +reverb 24 +.channel chan_E23 +ldlayer 0, layer_EAD +ldlayer 1, layer_EA7 +ldi 1 +stio 7 +.channel chan_E2C +delay1 +ldio 0 +stio 2 +rbeqz chan_E5C +ldio 1 +sub 0 +rbeqz chan_E58 +ldio 7 +sub 1 +stio 7 +rbeqz chan_E3E +rjump chan_E2C +.channel chan_E3E +rand 90 +stseq 10, layer_EBC+1 +stseq 10, layer_EBF+1 +rand 40 +stseq 68, layer_EB8+3 +stseq 68, layer_EBF +stio 6 +ldi 50 +stio 7 +rjump chan_E2C +.channel chan_E58 +dellayer 0 +dellayer 1 +rjump chan_E13 +.channel chan_E5C +vol 115 +ldio 5 +bgez chan_E64 +ldi 0 +.channel chan_E64 +and 63 +stio 5 +ldi 63 +subio 5 +sub 208 +stseq 0, chan_E72+1 +rand 16 +.channel chan_E72 +stseq 100, layer_ECF+3 +ldi 63 +subio 5 +ldseq addr_FBA +ldseq addr_F7A +stio 4 +stseq 103, chan_E87+1 +rand 2 +stio 3 +.channel chan_E87 +stseq 103, layer_ECF +rand 30 +stseq 49, layer_ECB+1 +stio 6 +ldlayer 0, layer_EC7 +ldlayer 1, layer_EC5 +.channel chan_E98 +delay1 +ldio 0 +rbeqz chan_E5C +ldio 1 +sub 0 +rbeqz chan_E58 +testlayer 0 +rbeqz chan_E98 +jump chan_E23 + +.layer layer_EA7 +transpose -12 +.layer layer_EA9 +stereo 20 +rjump layer_EAD + +.layer layer_EAD +instr FONT02_INSTR_THUNDER_RUMBLE +env envelope_101E, 97 +.layer layer_EB3 +portamento 0x85, 27, 255 +legato +.layer layer_EB8 +notedv PITCH_A2, 0x1C2, 110 +.layer layer_EBC +notedv PITCH_A2, 0x64, 110 +.layer layer_EBF +ldelay 0x60 +nolegato +noportamento +rjump layer_EB3 + +.layer layer_EC5 +transpose -12 + +.layer layer_EC7 +instr FONT02_INSTR_THUNDER_PEAL +releaserate 97 +.layer layer_ECB +notepan 64 +ldelay 0x1 +.layer layer_ECF +notedv PITCH_C4, 0xC8, 127 +.layer layer_ED3 +stereo 20 +notedv PITCH_A1, 0x28, 80 +stereo 0 +end + +.channel chan_EDB +ldio 7 +sub 2 +rbeqz chan_EE4 +ldi 0 +rjump chan_EE6 +.channel chan_EE4 +ldi 20 +.channel chan_EE6 +stseq 0, addr_EFB +stseq 0, layer_DFF+1 +stseq 0, layer_EA9+1 +stseq 0, layer_ED3+1 +stseq 0, layer_362+1 +end + +.array addr_EFB +byte 0x0 + +.layer layer_fn_EFC +ldelay 0x64 +.layer layer_EFE +ldelay 0x7F +.layer layer_F00 +stereo 0 +end + +.layer layer_fn_F03 +ldelay 0x64 +.layer layer_F05 +ldelay 0x7F +.layer layer_F07 +stereo 0 +end + +.layer layer_fn_F0A +ldelay 0x64 +.layer layer_F0C +ldelay 0x7F +.layer layer_F0E +stereo 0 +end + +.layer layer_fn_F11 +ldelay 0x64 +.layer layer_F13 +ldelay 0x7F +.layer layer_F15 +stereo 0 +end + +.layer layer_fn_F18 +ldelay 0x64 +.layer layer_F1A +ldelay 0x7F +.layer layer_F1C +stereo 0 +end + +.layer layer_fn_F1F +ldelay 0x64 +.layer layer_F21 +ldelay 0x7F +.layer layer_F23 +stereo 0 +end + +.layer layer_fn_F26 +ldelay 0x64 +.layer layer_F28 +ldelay 0x7F +.layer layer_F2A +stereo 0 +end + +.layer layer_fn_F2D +ldelay 0x64 +.layer layer_F2F +ldelay 0x7F +.layer layer_F31 +stereo 0 +end + +.layer layer_fn_F34 +ldelay 0x64 +.layer layer_F36 +ldelay 0x7F +.layer layer_F38 +stereo 0 +end + +.layer layer_fn_F3B +ldelay 0x64 +.layer layer_F3D +ldelay 0x7F +.layer layer_F3F +stereo 0 +end + +.layer layer_fn_F42 +ldelay 0x64 +.layer layer_F44 +ldelay 0x7F +.layer layer_F46 +stereo 0 +end + +.layer layer_fn_F49 +ldelay 0x64 +.layer layer_F4B +ldelay 0x7F +.layer layer_F4D +stereo 0 +end + +.layer layer_fn_F50 +ldelay 0x64 +.layer layer_F52 +ldelay 0x7F +.layer layer_F54 +stereo 0 +end + +.layer layer_fn_F57 +ldelay 0x64 +.layer layer_F59 +ldelay 0x7F +.layer layer_F5B +stereo 0 +end + +.layer layer_fn_F5E +ldelay 0x64 +.layer layer_F60 +ldelay 0x7F +.layer layer_F62 +stereo 0 +end + +.layer layer_fn_F65 +ldelay 0x64 +.layer layer_F67 +ldelay 0x7F +.layer layer_F69 +stereo 0 +end + +.layer layer_fn_F6C +ldelay 0x64 +.layer layer_F6E +ldelay 0x7F +.layer layer_F70 +stereo 0 +end + +.layer layer_fn_F73 +ldelay 0x64 +.layer layer_F75 +ldelay 0x7F +.layer layer_F77 +stereo 0 +end + +.array addr_F7A +byte 0x0 +byte 0x0 +byte 0x1 +byte 0x1 +byte 0x2 +byte 0x2 +byte 0x3 +byte 0x3 +byte 0x4 +byte 0x4 +byte 0x5 +byte 0x5 +byte 0x6 +byte 0x6 +byte 0x7 +byte 0x7 +byte 0x8 +byte 0x8 +byte 0x9 +byte 0x9 +byte 0xA +byte 0xA +byte 0xB +byte 0xB +byte 0xC +byte 0xC +byte 0xD +byte 0xD +byte 0xE +byte 0xE +byte 0xF +byte 0xF +byte 0x10 +byte 0x10 +byte 0x11 +byte 0x11 +byte 0x12 +byte 0x12 +byte 0x13 +byte 0x13 +byte 0x14 +byte 0x14 +byte 0x15 +byte 0x15 +byte 0x16 +byte 0x16 +byte 0x17 +byte 0x17 +byte 0x18 +byte 0x18 +byte 0x19 +byte 0x19 +byte 0x1A +byte 0x1A +byte 0x1B +byte 0x1B +byte 0x1C +byte 0x1C +byte 0x1D +byte 0x1D +byte 0x1E +byte 0x1E +byte 0x1F +byte 0x1F + +.array addr_FBA +byte 0x0 +byte 0x0 +byte 0x0 +byte 0x0 +byte 0x1 +byte 0x1 +byte 0x1 +byte 0x1 +byte 0x2 +byte 0x2 +byte 0x2 +byte 0x2 +byte 0x3 +byte 0x3 +byte 0x3 +byte 0x3 +byte 0x4 +byte 0x4 +byte 0x4 +byte 0x4 +byte 0x5 +byte 0x5 +byte 0x5 +byte 0x5 +byte 0x6 +byte 0x6 +byte 0x6 +byte 0x6 +byte 0x7 +byte 0x7 +byte 0x7 +byte 0x7 +byte 0x8 +byte 0x8 +byte 0x8 +byte 0x8 +byte 0x9 +byte 0x9 +byte 0x9 +byte 0x9 +byte 0xA +byte 0xA +byte 0xA +byte 0xA +byte 0xB +byte 0xB +byte 0xB +byte 0xB +byte 0xC +byte 0xC +byte 0xC +byte 0xC +byte 0xD +byte 0xD +byte 0xD +byte 0xD +byte 0xE +byte 0xE +byte 0xE +byte 0xE +byte 0xF +byte 0xF +byte 0xF +byte 0xF + +.envelope envelope_FFA +point 270, 32700 +.envelope envelope_FFE +point 125, 32700 +goto 1 + +.envelope envelope_1006 +point 25, 32700 +point 310, 5000 +hang + +.envelope envelope_1012 +point 2000, 32700 +point 32700, 32700 +hang + +.envelope envelope_101E +point 100, 32700 +point 2000, 10000 +hang + +.filter filter_1030 +filter 0, 0, 0, 0, 0, 0, 0, 0 diff --git a/assets/sequences/002_Hyrule_Field_Program.prg.seq b/assets/sequences/002_Hyrule_Field_Program.prg.seq new file mode 100644 index 00000000000..c7bec074b1b --- /dev/null +++ b/assets/sequences/002_Hyrule_Field_Program.prg.seq @@ -0,0 +1,234 @@ +.desc title "Hyrule Field Program" +.desc type "program" +.usefont SOUNDFONT_ORCHESTRA + +.sequence sequence_start + +# io slot 0 = temp, for communicating with loaded seqs. Initially time of day, with 1 = morning +# io slot 1 = temp, for seq loading +# io slot 2 = new external state (input from the game) +# io slot 3 = current external state (0, 1 or 2) +# io slot 4 = current internal state (0, 1 or 2, same as slot 3) +# io slot 5 = last random index +# io slot 6 = which sequence buffer to load into next (either 0 or 1) + +mutebhv 0x20 +mutescale 70 +initchan 0xFFFF +ldi 0 +stio 3 # set current external state = 0 (moving) +stio 6 # set buffer index = 0 +ldi 255 +stio 5 # set last random index = -1 + +# Play intro sequence (either morning version or default) +ldio 0 +sub 1 +rbeqz morning +ldi 3 # "Initial Segment From Loading Area" +call playseq +rjump state_moving +.sequence morning +ldi 49 # "Hyrule Field Morning Theme" +call playseq + +.sequence state_moving +ldi 0 +stio 4 # set internal state = 0 +ldio 2 +rbltz playrandom_moving # if new state = -1, goto moving +subio 3 +rbeqz playrandom_moving # if external state is unchanged, goto moving +ldio 2 +stio 3 # set external state = new state +sub 1 +rbeqz state_enemy_intro # if new state = 1, goto enemy +ldio 2 +sub 2 +rbeqz state_still_intro # if new state = 2, goto still + +# Play a random sequence from among 4..14, but not the same as last time. +# (If the same sequence is chosen as last time, choose the one just before it instead.) +.sequence playrandom_moving +rand 11 +subio 5 +rbeqz same_moving +rand 11 # same audio frame, so reads the same random value as before +rjump play_moving +.sequence same_moving +rand 11 +rbeqz iszero_moving +sub 1 +rjump play_moving +.sequence iszero_moving +ldi 11 +sub 1 +.sequence play_moving +stio 5 +sub 252 # += 4 +call playseq +rjump state_moving + +.sequence state_enemy_intro +ldi 1 +stio 4 # set internal state = 1 +ldi 255 +stio 5 # set last random index = -1 +ldi 15 # "Enemy Approaches" +call playseq + +.sequence state_enemy +ldio 2 +rbltz playrandom_enemy # if new state = -1, goto enemy +subio 3 +rbeqz playrandom_enemy # if external state is unchanged, goto enemy +ldio 2 +stio 3 # set external state = new state +rbeqz state_moving # if new state = 0, goto moving +sub 2 +rbeqz state_still_intro # if new state = 2, goto still + +# Play a random sequence from among 16..19, but not the same as last time. +.sequence playrandom_enemy +rand 4 +subio 5 +rbeqz same_enemy +rand 4 +rjump play_enemy +.sequence same_enemy +rand 4 +rbeqz iszero_enemy +sub 1 +rjump play_enemy +.sequence iszero_enemy +ldi 4 +sub 1 +.sequence play_enemy +stio 5 +sub 240 # += 16 +call playseq +rjump state_enemy + +.sequence state_still_intro +ldi 2 +stio 4 # set internal state = 2 +ldi 255 +stio 5 # set last random index = -1 +ldi 20 # "Standing Still Segment 1" +call playseq + +.sequence state_still +ldio 2 +rbltz playrandom_still # if new state = -1, goto still +subio 3 +rbeqz playrandom_still # if external state is unchanged, goto still +ldio 2 +stio 3 +rbeqz state_moving # if new state = 0, goto moving +sub 1 +rbeqz state_enemy_intro # if new state = 1, goto enemy + +# Play a random sequence from among 21..23, but not the same as last time. +.sequence playrandom_still +rand 3 +subio 5 +rbeqz same_still +rand 3 +rjump play_still +.sequence same_still +rand 3 +rbeqz iszero_still +sub 1 +rjump play_still +.sequence iszero_still +ldi 3 +sub 1 +.sequence play_still +stio 5 +sub 235 # += 21 +call playseq +rjump state_still + +.table loadseq_fns +entry loadseq1 +entry loadseq2 + +.table playseq_fns +entry seqbuf1 +entry seqbuf2 + +# Play the sequence given by the temp register +.sequence playseq +stio 7 + +# Write 0 to port 0 to tell the top-level sequence script that we load to +# return 30 ticks early, so we have time to load the next sequence. +# Sound will continue playing during those 30 ticks. +ldi 0 +stio 0 + +# Load the chosen sequence into the free buffer. This may take a few ticks. +ldio 6 +dyncall loadseq_fns + +# Wait for previous sequence to finish playing. +.sequence playseq_retry +delay1 +testchan 0 +rbeqz playseq_retry +testchan 6 +rbeqz playseq_retry +testchan 9 +rbeqz playseq_retry +testchan 10 +rbeqz playseq_retry +testchan 12 +rbeqz playseq_retry +testchan 14 +rbeqz playseq_retry +ldio 6 +dyncall playseq_fns +ldi 1 +subio 6 +stio 6 # set buffer index = 1 - buffer index +end + +# Synchronously load the sequence specified by io slot 7 at .seqbuf1 +.sequence loadseq1 +ldio 7 +stseq 0, loadseq1instr+1 +ldi 255 +stio 1 +.sequence loadseq1instr +ldseq 1, 2, seqbuf1 +rjump loadseq_loop + +# Synchronously load the sequence specified by io slot 7 at .seqbuf2 +.sequence loadseq2 +ldio 7 +stseq 0, loadseq2instr+1 +ldi 255 +stio 1 +.sequence loadseq2instr +ldseq 1, 2, seqbuf2 + +# Wait for the sequence to load. This will be signalled by a write to io port 1, +# as specified by the ldseq call. +.sequence loadseq_loop +delay1 +ldio 1 +rbeqz loadseq_done +rbltz loadseq_loop +end +.sequence loadseq_done +end + +.buffer seqbuf1 +space 4600 + +# The alignment of this buffer is off by 8 bytes. In practice this ends up +# working anyway, as it DMAs 8 bytes into the buffer and the first 8 bytes are +# interpreted as "testchan 0", which has no effect. +.balign 8 +.buffer seqbuf2 +space 4600 diff --git a/assets/sequences/109_Cutscene_Effects.prg.seq b/assets/sequences/109_Cutscene_Effects.prg.seq new file mode 100644 index 00000000000..5e627879a9f --- /dev/null +++ b/assets/sequences/109_Cutscene_Effects.prg.seq @@ -0,0 +1,1147 @@ +.desc title "Cutscene Sounds" +.desc type "program" +.usefont SOUNDFONT_SFX_2 +.usefont SOUNDFONT_SFX_1 + +.sequence sequence_start +mutebhv 0x60 +mutescale 0 +vol 127 +tempo 120 +initchan 0x1 +ldchan 0, chan_13 +.sequence seq_E +delay1 +testchan 0 +rbeqz seq_E +end + +.channel chan_13 +noshort +mutebhv 0x20 +effects 128 +notepri 14 +rvrbidx 1 +font SOUNDFONT_SFX_1 +reverb 15 +panweight 127 +dyntbl table_646 +ldio 0 +rbltz chan_2D +dyncall +.channel chan_29 +delay1 +testlayer 0 +rbeqz chan_29 +.channel chan_2D +end + +.channel sword_glow +reverb 30 +panweight 118 +ldlayer 0, layer_45 +ldlayer 1, layer_58 +ldlayer 2, layer_71 +cdelay 1 +vibdepthgrad 60, 0, 18 +vibfreqgrad 240, 20, 18 +end + +.layer layer_45 +notepan 127 +instr FONT00_INSTR_WARP +transpose 24 +env envelope_78A, 230 +notedv PITCH_A4, 0x10E, 80 +notedv PITCH_A5, 0x12C, 80 +end + +.layer layer_58 +notepan 0 +ldelay 0x1 +instr FONT00_INSTR_WATER_FLOWING +transpose 48 +env envelope_78A, 180 +portamento 0x81, 56, 255 +notedv PITCH_F5, 0xFA, 72 +notedv PITCH_A5, 0x140, 72 +end + +.layer layer_71 +ldelay 1 +instr FONT00_INSTR_SHIMMER +env envelope_78A, 230 +# The last argument here is represented with a single byte, even though the format +# should use two bytes instead. +portamentofix 0x1, 15, 133 +noportamento +notedv PITCH_C5, 0x23A, 64 +end + +.channel sheik_transform +ldlayer 0, layer_99 +ldlayer 1, layer_A6 +ldlayer 2, layer_B7 +cdelay 1 +vibfreqgrad 127, 255, 40 +vibdepthgrad 20, 127, 40 +cdelay 1 +vibdepth 0 +end + +.layer layer_99 +instr FONT00_INSTR_WARP +env envelope_8D2, 221 +transpose 24 +notedv PITCH_C5, 0x190, 105 +end + +.layer layer_A6 +ldelay 0x1 +instr FONT00_INSTR_FAIRY_MAGIC +env envelope_90A, 224 +portamento 0x81, 3, 255 +notedv PITCH_E3, 0x12C, 65 +end + +.layer layer_B7 +instr FONT00_INSTR_SYNTH +portamento 0x81, 24, 25 +notedv PITCH_D3, 0x46, 85 +ldelay 0xC8 +env envelope_916, 221 +portamento 0x81, 27, 25 +notedv PITCH_F3, 0x96, 85 +end + +.channel sage_seal +ldlayer 0, layer_F7 +ldlayer 1, layer_DE +ldlayer 2, layer_EF +vibfreq 255 +vibdepth 40 +end + +.layer layer_DE +transpose 48 +instr FONT00_INSTR_EYE_OF_TRUTH +releaserate 221 +portamento 0x84, 22, 127 +notedv PITCH_A4, 0x60, 85 +notedv PITCH_B4, 0x7F, 95 +end + +.layer layer_EF +instr FONT00_INSTR_EXPLOSION_0 +env envelope_72A, 221 +rjump layer_FD + +.layer layer_F7 +instr FONT00_INSTR_SLIDE_LINK +transpose 36 +releaserate 221 +.layer layer_FD +portamento 0x85, 46, 255 +notedv PITCH_A2, 0x3C, 90 +env envelope_712, 221 +notedv PITCH_A3, 0x24, 90 +portamento 0x85, 51, 255 +notedv PITCH_C3, 0x7F, 90 +end + +.channel nayru_magic +ldlayer 0, layer_127 +ldlayer 1, layer_11A +end + +.layer layer_11A +transpose 36 +instr FONT00_INSTR_SHIMMER +env envelope_87A, 180 +notedv PITCH_E4, 0x226, 70 +end + +.layer layer_127 +transpose 30 +instr FONT00_INSTR_WARP +env envelope_87A, 221 +notedv PITCH_F3, 0x9B, 100 +notedv PITCH_F4, 0x7F, 100 +transpose 36 +instr FONT00_INSTR_WARP +env envelope_88A, 221 +notedv PITCH_C4, 0xF8, 100 +end + +.channel farore_magic +ldlayer 0, layer_14D +ldlayer 1, layer_127 +ldlayer 2, layer_11A +end + +.layer layer_14D +ldelay 0x190 +end + +.channel din_magic +reverb 30 +ldlayer 1, layer_172 + +.channel lava_erupt +instr FONT00_INSTR_DISTORTION +ldlayer 0, layer_165 +ldlayer 2, layer_182 +vibfreq 160 +vibdepthgrad 0, 48, 9 +end + +.layer layer_165 +env envelope_78A, 231 +portamento 0x81, 38, 255 +notedv PITCH_F3, 0x24E, 75 +end + +.layer layer_172 +ldelay 0x15E +env envelope_792, 231 +portamento 0x81, 3, 255 +notedv PITCH_C3, 0xF0, 100 +end + +.layer layer_182 +instr FONT00_INSTR_MECH_CHARGE +env envelope_792, 231 +notedv PITCH_AF3, 0x208, 92 +end + +.channel bongo_hurl_link +ldchan 1, chan_251 +ldlayer 0, layer_1D4 +ldlayer 1, layer_1E9 +ldlayer 2, layer_243 +pan 58 +delay 0x30 +transpose 1 +ldlayer 0, layer_1D4 +ldlayer 1, layer_1E9 +ldlayer 2, layer_24A +pan 70 +delay 0x47 +transpose 2 +ldlayer 0, layer_1D4 +ldlayer 1, layer_1E9 +ldlayer 2, layer_1FA +pan 64 +delay 0x8E +transpose 0 +ldlayer 0, layer_201 +ldlayer 1, layer_210 +ldlayer 2, layer_21B +ldlayer 3, layer_236 +gain 25 +delay 0x64 +gain 0 +delay 0x1E0 +end + +.layer layer_1D4 +instr FONT00_INSTR_SWORD_SWING +env envelope_75E, 251 +portamento 0x81, 55, 127 +notedv PITCH_DF1, 0x8, 115 +portamento 0x81, 6, 255 +notedv PITCH_AF3, 0xB, 105 +end + +.layer layer_1E9 +instr FONT00_INSTR_WHISTLE_AIR +portamento 0x81, 49, 222 +notedv PITCH_BF2, 0x8, 115 +portamento 0x81, 19, 255 +notedv PITCH_F3, 0xC, 115 +end + +.layer layer_1FA +instr FONTANY_INSTR_SFX +notedvg FONT00_EFFECT_LINK_ADULT_FALL_0, 0x0, 100, 0 +end + +.layer layer_201 +instr FONT00_INSTR_SLAM_GUNSHOT +env envelope_746, 250 +portamento 0x81, 38, 200 +notedvg PITCH_BF3, 0x24, 115, 100 +end + +.layer layer_210 +instr FONT00_INSTR_STEP_CARPET_0 +notedv PITCH_E4, 0xA, 75 +notedv PITCH_G3, 0xA, 75 +ldelay 0x7 +end + +.layer layer_21B +ldelay 0x7 +instr FONT00_INSTR_SWORD_HIT_SHIELD +env envelope_6F6, 250 +notedvg PITCH_C5, 0x6, 39, 127 +instr FONT00_INSTR_SWORD_STRIKE +notedvg PITCH_D4, 0x4, 49, 127 +instr FONT00_INSTR_STEP_FIRE +notedv PITCH_B3, 0x5, 39 +notedv PITCH_F3, 0x5, 39 +end + +.layer layer_236 +instr FONTANY_INSTR_SFX +notedvg FONT00_EFFECT_LINK_ADULT_HURT_4, 0x0, 95, 0 +ldelay 0x14 +notedvg FONT00_EFFECT_LINK_ADULT_HURT_4, 0xF, 90, 0 +end + +.layer layer_243 +instr FONTANY_INSTR_SFX +notedvg FONT00_EFFECT_LINK_ADULT_HURT_1, 0x0, 100, 0 +end + +.layer layer_24A +instr FONTANY_INSTR_SFX +notedvg FONT00_EFFECT_LINK_ADULT_HURT_3, 0x0, 110, 0 +end + +.channel chan_251 +noshort +mutebhv 0x20 +effects 128 +notepri 14 +rvrbidx 1 +reverb 15 +font SOUNDFONT_SFX_2 +ldlayer 0, layer_2AE +ldlayer 2, layer_2C3 +vibfreq 96 +vibdepth 84 +delay 0x17C +cdelay 10 +pan 60 +cdelay 10 +pan 56 +cdelay 10 +pan 52 +cdelay 10 +pan 48 +cdelay 10 +pan 52 +cdelay 10 +pan 56 +cdelay 10 +pan 60 +cdelay 10 +pan 64 +cdelay 10 +pan 68 +cdelay 10 +pan 72 +cdelay 10 +pan 76 +cdelay 10 +pan 80 +cdelay 10 +pan 86 +cdelay 10 +pan 94 +cdelay 10 +pan 104 +cdelay 10 +pan 116 +cdelay 10 +pan 127 +cdelay 10 +pan 124 +cdelay 10 +pan 120 +cdelay 10 +pan 116 +cdelay 10 +pan 112 +delay 0x118 +end + +.layer layer_2AE +transpose -4 +instr FONT01_INSTR_DINO_INHALE +env envelope_8C2, 251 +.layer layer_2B6 +legato +portamento 0x85, 24, 255 +.layer layer_2BB +notedv PITCH_A3, 0x64, 90 +notedv PITCH_A2, 0x64, 90 +rjump layer_2BB + +.layer layer_2C3 +transpose 4 +instr FONT01_INSTR_BOULDER +env envelope_8C2, 251 +.layer layer_2CB +legato +portamento 0x85, 48, 255 +.layer layer_2D0 +notedv PITCH_A5, 0x32, 76 +notedv PITCH_A4, 0x32, 76 +rjump layer_2D0 + +.channel bongo_hover +ldlayer 0, layer_2E8 +ldlayer 1, layer_2EC +ldlayer 2, layer_2F6 +font SOUNDFONT_SFX_2 +vibfreq 96 +vibdepth 84 +end + +.layer layer_2E8 +ldelay 0x750 +end + +.layer layer_2EC +transpose -4 +instr FONT01_INSTR_DINO_INHALE +env envelope_8EA, 251 +rjump layer_2B6 + +.layer layer_2F6 +transpose 4 +instr FONT01_INSTR_BOULDER +env envelope_8EA, 251 +rjump layer_2CB + +.channel bongo_death +font SOUNDFONT_SFX_2 +ldchan 1, chan_344 +delay 0x102 +ldlayer 0, layer_312 +ldlayer 1, layer_32C +delay 0x47E +end + +.layer layer_312 +instr FONT01_INSTR_MONSTER_ROAR +env envelope_916, 221 +notedvg PITCH_GF4, 0x64, 90, 50 +portamento 0x81, 48, 255 +notedv PITCH_C4, 0x64, 90 +portamento 0x81, 50, 100 +notedv PITCH_C2, 0x1F4, 90 +end + +.layer layer_32C +instr FONT01_INSTR_THUNDER_HURT +releaserate 221 +notedvg PITCH_E4, 0x64, 90, 50 +portamento 0x81, 46, 255 +notedv PITCH_B3, 0x64, 90 +portamento 0x81, 48, 100 +notedv PITCH_B1, 0x1F4, 90 +end + +.channel chan_344 +noshort +mutebhv 0x20 +effects 128 +notepri 14 +rvrbidx 1 +reverb 15 +ldlayer 0, layer_36A +ldlayer 1, layer_375 +font SOUNDFONT_SFX_2 +vibfreq 96 +vibdepth 84 +transpose -12 +delay 0x102 +transpose 4 +delay 0x47E +.channel chan_365 +delay1 +testlayer 0 +rbeqz chan_365 +end + +.layer layer_36A +transpose -4 +instr FONT01_INSTR_DINO_INHALE +env envelope_91E, 200 +jump layer_2B6 + +.layer layer_375 +transpose 4 +instr FONT01_INSTR_BOULDER +env envelope_91E, 200 +jump layer_2CB + +.channel trial_warp +reverb 40 +ldlayer 0, layer_38E +ldlayer 1, layer_38C +ldlayer 2, layer_39D +end + +.layer layer_38C +transpose -4 + +.layer layer_38E +instr FONT00_INSTR_WIND_HOWL_S +env envelope_78A, 241 +portamento 0x81, 3, 224 +notedv PITCH_B4, 0xC6, 80 +end + +.layer layer_39D +instr FONT00_INSTR_SLIDE_HEAVY +env envelope_86E, 221 +transpose 12 +portamento 0x81, 2, 255 +notedv PITCH_B5, 0xFA, 85 +end + +.channel trial_destroy +instr FONT00_INSTR_SHIMMER +reverb 40 +ldlayer 0, layer_3C5 +ldlayer 1, layer_3D7 +ldlayer 2, layer_3DB +ldlayer 3, layer_3EC +vibdepthgrad 255, 60, 10 +vibfreq 150 +end + +.layer layer_3C5 +instr FONT00_INSTR_POTTERY_ELECTRIC +env envelope_6CE, 245 +portamento 0x82, 27, 255 +notedv PITCH_C4, 0x96, 80 +ldelay 0x96 +end + +.layer layer_3D7 +notedv PITCH_C3, 0x64, 85 +end + +.layer layer_3DB +transpose 24 +instr FONT00_INSTR_SLIDE_BLOCK +env envelope_78A, 200 +portamento 0x82, 51, 180 +notedv PITCH_B5, 0xB4, 75 +end + +.layer layer_3EC +instr FONT00_INSTR_SYNTH_BUZZ +portamento 0x81, 34, 208 +notedv PITCH_D3, 0xF0, 105 +end + +.layer layer_unused_3F7 +instr FONT00_INSTR_WHOOSH +portamento 0x81, 10, 44 +notedv PITCH_G2, 0x8C, 75 +end + +.channel dispel_barrier +panweight 48 +vol 78 +reverb 55 +ldchan 1, chan_467 +ldlayer 0, layer_44C +ldlayer 1, layer_424 +ldlayer 2, layer_445 +ldlayer 3, layer_43B +vibfreq 20 +vibdepth 70 +delay 0x60 +vibfreqgrad 20, 150, 60 +vibdepth 70 +end + +.layer layer_424 +instr FONT00_INSTR_FLAME_THUNDER +env envelope_78A, 211 +legato +portamento 0x85, 3, 255 +notedv PITCH_F2, 0x60, 100 +notedv PITCH_F2, 0xC8, 100 +notedv PITCH_F3, 0x12C, 74 +end + +.layer layer_43B +instr FONT00_INSTR_FLUTE +transpose 24 +notepan 88 +ldelay 0x4 +rjump layer_452 + +.layer layer_445 +transpose -18 +instr FONT00_INSTR_OCARINA_0 +jump layer_452 + +.layer layer_44C +instr FONT00_INSTR_WARP +transpose 12 +notepan 40 +.layer layer_452 +env envelope_78A, 211 +legato +portamento 0x85, 15, 255 +notedv PITCH_F3, 0x60, 74 +notedv PITCH_F3, 0xC8, 74 +notedv PITCH_F4, 0x12C, 74 +end + +.channel chan_467 +noshort +mutebhv 0x20 +effects 128 +notepri 14 +rvrbidx 1 +reverb 40 +font SOUNDFONT_SFX_1 +call lava_erupt +delay 0x60 +call lava_erupt +ldlayer 1, layer_486 +ldlayer 3, layer_498 +delay 0x3E8 +end + +.layer layer_486 +instr FONT00_INSTR_SLIDE_BLOCK +env envelope_78A, 231 +ldelay 0x96 +portamento 0x81, 27, 255 +notedv PITCH_C5, 0x1B8, 45 +end + +.layer layer_498 +instr FONT00_INSTR_EXPLOSION_0 +env envelope_792, 231 +ldelay 0xDC +portamento 0x81, 15, 255 +notedv PITCH_C3, 0x172, 110 +end + +.channel tower_collapse +ldchan 1, chan_4BC +vol 105 +ldlayer 0, layer_545 +ldlayer 1, layer_536 +ldlayer 2, layer_571 +ldlayer 3, layer_566 +end + +.channel chan_4BC +noshort +mutebhv 0x20 +effects 128 +notepri 14 +rvrbidx 1 +reverb 40 +vol 105 +panweight 64 +ldlayer 0, layer_4F5 +ldlayer 1, layer_4DB +ldlayer 2, layer_514 +ldlayer 3, layer_50E +delay 0x1388 +end + +.layer layer_4DB +instr FONT00_INSTR_EXPLOSION_0 +env envelope_792, 221 +stereo 20 +notepan 84 +notedv PITCH_F2, 0x91, 72 +.layer layer_4E9 +notedv PITCH_D3, 0x5A, 70 +notedv PITCH_F3, 0xE1, 74 +notedv PITCH_A2, 0x61, 68 +rjump layer_4E9 + +.layer layer_4F5 +instr FONT00_INSTR_EXPLOSION_0 +env envelope_792, 221 +stereo 20 +notepan 44 +notedv PITCH_D3, 0x10B, 72 +.layer layer_503 +notedv PITCH_C3, 0x5E, 40 +notedv PITCH_D3, 0x7C, 44 +notedv PITCH_B2, 0x30, 68 +rjump layer_503 + +.layer layer_50E +transpose -12 +instr FONT00_INSTR_MECH_CHARGE +rjump layer_51A + +.layer layer_514 +instr FONT00_INSTR_EXPLOSION_0 +env envelope_71E, 230 +.layer layer_51A +ldelay 0xA82 +portamento 0x81, 55, 60 +notedv PITCH_C2, 0xC0, 100 +portamento 0x81, 58, 60 +notedv PITCH_E2, 0xC0, 100 +portamento 0x81, 62, 45 +notedv PITCH_G2, 0x1F4, 100 +end + +.layer layer_536 +transpose -6 +call layer_fn_552 +nolegato +noportamento +instr FONT00_INSTR_BLOCK_LOCK +ldelay 0x14 +transpose -3 +rjump layer_589 + +.layer layer_545 +call layer_fn_552 +nolegato +noportamento +instr FONT00_INSTR_MECH_CHARGE +ldelay 0xA +transpose 10 +rjump layer_589 + +.layer layer_fn_552 +instr FONT00_INSTR_MECH_CHARGE +env envelope_792, 211 +legato +portamento 0x85, 51, 255 +notedv PITCH_E5, 0xC8, 90 +notedv PITCH_G5, 0x979, 80 +end + +.layer layer_566 +transpose 5 +call layer_fn_581 +ldelay 0x14 +instr FONT00_INSTR_MECH_CHARGE +rjump layer_589 + +.layer layer_571 +call layer_fn_581 +instr FONT00_INSTR_BLOCK_LOCK +rjump layer_589 + +.layer layer_unused_578 +env envelope_792, 200 +legato +portamento 0x81, 17, 255 + +.layer layer_fn_581 +instr FONT00_INSTR_DOOR_METAL +notedv PITCH_A2, 0xA41, 65 +nolegato +end +.layer layer_589 +notedv PITCH_E3, 0xC0, 120 +notedv PITCH_G3, 0xC0, 120 +releaserate 160 +notedv PITCH_A3, 0xC0, 120 +end + +.channel link_scream +vol 110 +instr FONTANY_INSTR_SFX +ldfilter filter_5B0 +filter 64 +reverb 40 +gain 25 +ldlayer 0, layer_5A9 +end + +.layer layer_5A9 +notedv FONT00_EFFECT_LINK_CHILD_FALL_1, 0x0, 110 +end + +.filter filter_5B0 +filter 0, 0, 0, 0, 0, 0, 0, 0 + +.channel rainfall +instr FONTANY_INSTR_DRUM +env envelope_90A +releaserate 200 +panweight 0 +ldlayer 0, layer_5DA +ldlayer 1, layer_5E0 +ldchan 1, chan_5E6 +delay 0x708 +dellayer 0 +dellayer 1 +delay 0x64 +end + +.layer layer_5DA +legato +.layer layer_5DB +notedv FONT00_DRUM_RAIN_1, 0x64, 80 +rjump layer_5DB + +.layer layer_5E0 +legato +.layer layer_5E1 +notedv FONT00_DRUM_RAIN_0, 0x64, 80 +rjump layer_5E1 + +.channel chan_5E6 +noshort +mutebhv 0x20 +effects 128 +notepri 14 +rvrbidx 1 +reverb 20 +vol 100 +gain 15 +delay 0x240 +ldlayer 0, layer_633 +ldlayer 1, layer_62F +ldlayer 2, layer_63F +vol 75 +delay 0xC8 +ldlayer 0, layer_633 +ldlayer 1, layer_62F +ldlayer 2, layer_63F +vol 110 +delay 0x87 +ldlayer 0, layer_633 +ldlayer 1, layer_62F +ldlayer 2, layer_63F +vol 95 +delay 0x156 +ldlayer 0, layer_633 +ldlayer 1, layer_62F +ldlayer 2, layer_63F +delay 0xFA +end + +.layer layer_62F +transpose 36 +rjump layer_635 + +.layer layer_633 +transpose 48 +.layer layer_635 +instr FONT00_INSTR_FLAME_THUNDER +env envelope_692, 200 +notedv PITCH_G4, 0x0, 110 +end + +.layer layer_63F +instr FONT00_INSTR_POTTERY_ELECTRIC +notedv PITCH_G3, 0x32, 50 +end + +.array unused_645 +byte 0x0 + +.table table_646 +entry sword_glow # FX0: Master sword glow +entry sheik_transform # FX1: Sheik's transformation to Zelda +entry sage_seal # FX2: Sages accumulating their power +entry nayru_magic # FX3: Nayru's magic establishing order +entry farore_magic # FX4: Farore's magic creating life +entry din_magic # FX5: Din's building of the earth +entry lava_erupt # FX6: Lava erupting from Volvagia's pit +entry bongo_hurl_link # FX7: Link screaming while attacked by invisible Bongo Bongo +entry bongo_hover # FX8: Bongo Bongo hovering menacingly +entry bongo_death # FX9: Bongo Bongo disintegrating +entry trial_warp # FXA: Warping from trial barrier +entry trial_destroy # FXB: Destroying the trial barrier +entry dispel_barrier # FXC: Dispelling the Tower barrier +entry tower_collapse # FXD: Ganon's Tower's collapse +entry link_scream # FXE: Child Link screaming (unused) +entry rainfall # FXF: Rain with thunder effects + +.envelope envelope_unused_666 +point 1, 32700 +hang + +.envelope envelope_unused_66E +point 1, 32700 +point 100, 30000 +point 200, 5000 +hang + +.envelope envelope_unused_67E +point 1, 32700 +point 25, 25000 +point 100, 25000 +point 200, 5000 +hang + +.envelope envelope_692 +point 1, 32700 +point 100, 30000 +point 250, 30000 +point 200, 5000 +hang + +.envelope envelope_unused_6A6 +point 1, 32700 +point 50, 30000 +point 100, 10000 +point 100, 0 +hang + +.envelope envelope_unused_6BA +point 1, 32700 +point 30, 30000 +point 50, 10000 +point 50, 0 +hang + +.envelope envelope_6CE +point 1, 32700 +point 70, 30000 +point 120, 10000 +point 120, 0 +hang + +.envelope envelope_unused_6E2 +point 1, 32700 +point 15, 32700 +point 15, 22000 +point 100, 15000 +hang + +.envelope envelope_6F6 +point 1, 32700 +point 8, 32700 +point 8, 22000 +point 100, 15000 +hang + +.envelope envelope_unused_70A +point 10, 32700 +hang + +.envelope envelope_712 +point 30, 10000 +point 30, 32700 +hang + +.envelope envelope_71E +point 20, 15000 +point 10, 32700 +hang + +.envelope envelope_72A +point 48, 10000 +point 32, 32700 +hang + +.envelope envelope_unused_736 +point 47, 15000 +point 13, 32700 +point 72, 10000 +hang + +.envelope envelope_746 +point 6, 32700 +hang + +.envelope envelope_unused_74E +point 20, 32700 +point 50, 10000 +point 40, 0 +hang + +.envelope envelope_75E +point 18, 32700 +hang + +.envelope envelope_unused_766 +point 10, 32700 +point 240, 31000 +point 150, 2000 +hang + +.envelope envelope_unused_776 +point 14, 15000 +point 13, 32700 +hang + +.envelope envelope_unused_782 +point 40, 32700 +hang + +.envelope envelope_78A +point 400, 32700 +hang + +.envelope envelope_792 +point 100, 32700 +hang + +.envelope envelope_unused_79A +point 225, 32700 +point 30, 30000 +hang + +.envelope envelope_unused_7A6 +point 200, 32700 +hang + +.envelope envelope_unused_7AE +point 3, 32700 +hang + +.envelope envelope_unused_7B6 +point 12, 32700 +point 40, 5000 +hang + +.envelope envelope_unused_7C2 +point 10, 32700 +point 4, 20000 +point 4, 10000 +point 50, 2000 +hang + +.envelope envelope_unused_7D6 +point 40, 32700 +point 150, 32700 +point 300, 0 +hang + +.envelope envelope_unused_7E6 +point 40, 32700 +point 800, 32700 +point 100, 16000 +point 100, 32700 +point 100, 16000 +point 100, 32700 +point 100, 16000 +point 100, 32700 +point 600, 0 +hang + +.envelope envelope_unused_80E +point 200, 32700 +point 100, 16000 +point 100, 32700 +point 100, 16000 +point 100, 32700 +point 600, 0 +hang + +.envelope envelope_unused_82A +point 35, 32700 +point 40, 32700 +point 105, 0 +hang + +.envelope envelope_unused_83A +point 1, 25000 +point 12, 32700 +point 40, 32700 +point 60, 15000 +point 80, 5000 +hang + +.envelope envelope_unused_852 +point 10, 32700 +point 50, 32700 +point 60, 5000 +hang + +.envelope envelope_unused_862 +point 200, 32700 +point 340, 0 +hang + +.envelope envelope_86E +point 400, 32700 +point 400, 20000 +goto 0 + +.envelope envelope_87A +point 1400, 32700 +point 400, 14000 +point 400, 32700 +goto 1 + +.envelope envelope_88A +point 25, 32700 +point 490, 12000 +hang + +.envelope envelope_unused_896 +point 100, 32700 +point 450, 32700 +point 150, 32700 +point 1200, 32700 +point 400, 20000 +hang + +.envelope envelope_unused_8AE +point 200, 32700 +point 200, 20000 +goto 0 + +.envelope envelope_unused_8BA +point 2, 25000 +hang + +.envelope envelope_8C2 +point 1, 32700 +point 712, 32700 +point 900, 0 +hang + +.envelope envelope_8D2 +point 1, 32700 +point 200, 32700 +point 200, 16000 +point 200, 32700 +point 600, 0 +hang + +.envelope envelope_8EA +point 140, 20000 +point 2540, 10000 +point 200, 32700 +point 720, 20000 +point 240, 27000 +point 20, 16000 +point 940, 32700 +hang + +.envelope envelope_90A +point 100, 20000 +point 400, 32700 +hang + +.envelope envelope_916 +point 50, 32700 +hang + +.envelope envelope_91E +point 500, 25000 +point 675, 30000 +point 800, 25000 +point 20, 20000 +hang + +# It's impossible to tell if these were unused filters, envelopes only containing +# ADSR_DISABLE, or a buffer of size 0x20. Unused filters seems the most likely, so +# that's how this is represented here. +.filter unused_filter_940 +filter 0, 0, 0, 0, 0, 0, 0, 0 + +.filter unused_filter_950 +filter 0, 0, 0, 0, 0, 0, 0, 0 diff --git a/assets/sequences/sfxbanks/enemy.seq.inc b/assets/sequences/sfxbanks/enemy.seq.inc new file mode 100644 index 00000000000..31f5747c825 --- /dev/null +++ b/assets/sequences/sfxbanks/enemy.seq.inc @@ -0,0 +1,5964 @@ +.table table_enemy +entry enemy_dodongo_walk +entry enemy_dodongo_breathe +entry enemy_dodongo_flame +entry enemy_dodongo_hurt +entry enemy_dodongo_die +entry enemy_boss_dodongo_exhale +entry enemy_boss_dodongo_hurt +entry enemy_boss_dodongo_die +entry enemy_boss_dodongo_walk +entry enemy_boss_dodongo_flame +entry enemy_boss_gohma_walk +entry enemy_boss_gohma_walk_ceiling +entry enemy_boss_gohma_climb +entry enemy_boss_gohma_fall +entry enemy_boss_gohma_roar +entry enemy_boss_gohma_growl +entry enemy_boss_gohma_hurt +entry enemy_boss_gohma_hurt_eye +entry enemy_boss_gohma_die +entry enemy_boss_gohma_birth +entry enemy_larvae_egg_land +entry enemy_larvae_egg_break +entry enemy_larvae_walk +entry enemy_larvae_chirp +entry enemy_larvae_hurt +entry enemy_larvae_cry +entry enemy_larvae_die +entry enemy_boss_gohma_eyeroll +entry enemy_boss_gohma_dissolve +entry enemy_boss_gohma_thrust +entry enemy_boss_gohma_paralyzed +entry enemy_larvae_paralyzed +entry enemy_dodongo_jr_yell +entry enemy_dodongo_jr_die +entry enemy_dodongo_jr_walk +entry enemy_dodongo_jr_burrow +entry enemy_dodongo_jr_emerge +entry enemy_ganondorf_throw_orb +entry enemy_dodongo_jr_eat +entry enemy_ganondorf_hit_light +entry enemy_lizalfos_land +entry enemy_lizalfos_cry +entry enemy_lizalfos_attack_shout +entry enemy_lizalfos_hurt +entry enemy_lizalfos_laugh +entry enemy_lizalfos_die +entry enemy_lizalfos_walk +entry enemy_lizalfos_jump +entry enemy_stalkid_walk +entry enemy_stalkid_attack +entry enemy_stalkid_hurt +entry enemy_stalkid_die +entry enemy_floormaster_slide +entry enemy_tektite_turn_water +entry enemy_destroyed_light_arrow +entry enemy_pot_fly +entry enemy_stalfos_laugh +entry enemy_stalfos_attack +entry enemy_stalfos_hurt +entry enemy_stalfos_die +entry enemy_wolfos_spawn +entry enemy_stalfos_walk +entry enemy_wolfos_howl +entry enemy_wolfos_attack +entry enemy_keese_attack +entry enemy_keese_fly +entry enemy_keese_die +entry enemy_wolfos_hurt +entry enemy_armos_hop +entry enemy_armos_awaken +entry enemy_armos_die +entry enemy_armos_hurt +entry enemy_armos_roar +entry enemy_shell_open +entry enemy_shell_die +entry enemy_wolfos_die +entry enemy_boss_dodongo_demo_wall +entry enemy_boss_dodongo_wall_hit +entry enemy_boss_dodongo_roll +entry enemy_boss_dodongo_inhale +entry enemy_boss_dodongo_swallow +entry enemy_boss_dodongo_paralyzed +entry enemy_boss_dodongo_roar +entry enemy_boss_dodongo_dying_groan +entry enemy_boss_dodongo_fossilize +entry enemy_boss_dodongo_lava +entry enemy_ganondorf_fly +entry enemy_ganondorf_vortex_charge +entry enemy_dodongo_inhale +entry enemy_dodongo_swipe +entry enemy_wolfos_walk +entry enemy_dodongo_jr_eat +entry enemy_big_baba_chomp +entry enemy_big_baba_attack +entry enemy_big_baba_hurt +entry enemy_big_baba_die +entry enemy_deku_baba_chomp +entry enemy_deku_baba_attack +entry enemy_deku_baba_die +entry enemy_deku_baba_slide +entry enemy_tailpasaran_fly +entry enemy_tailpasaran_cry +entry enemy_tailpasaran_die +entry enemy_ganondorf_charge +entry enemy_skulltula_drop +entry enemy_skulltula_climb +entry enemy_skulltula_quiver +entry enemy_skulltula_hurt +entry enemy_stalfos_jump +entry enemy_tektite_hurt +entry enemy_tektite_die +entry enemy_tektite_turn_ground +entry enemy_poe_attack_charge +entry enemy_poe_float +entry enemy_poe_retreat +entry enemy_poe_appear +entry enemy_poe_vanish +entry enemy_poe_hurt +entry enemy_poe_die +entry enemy_poe_transform +entry enemy_dissolve +entry enemy_goron_land +entry enemy_lizalfos_land_flat +entry enemy_dodongo_jr_land +entry enemy_scrub_emerge +entry enemy_scrub_burrow +entry enemy_scrub_spit +entry enemy_scrub_walk +entry enemy_scrub_hurt +entry enemy_scrub_die +entry enemy_shop_scrub_cry +entry enemy_big_poe_get_soul +entry enemy_skulltula_pivot +entry enemy_skullwall_die +entry enemy_poe_sister_die +entry enemy_bari_split +entry enemy_tektite_flip +entry enemy_boss_gohma_fall +entry enemy_tektite_land_water1 +entry enemy_final_hit +entry enemy_skullwall_rotate +entry enemy_skullwall_dash +entry enemy_tektite_jump_water +entry enemy_tektite_land_water2 +entry enemy_wallmaster_fall +entry enemy_wallmaster_retreat +entry enemy_wallmaster_grab +entry enemy_larvae_egg_land +entry enemy_floormaster_walk +entry enemy_floormaster_hurt +entry enemy_floormaster_die +entry enemy_guay_fly +entry enemy_biri_float +entry enemy_biri_fly +entry enemy_biri_shock +entry enemy_biri_die +entry enemy_biri_die_bubbles +entry enemy_bari_spin +entry enemy_larvae_paralyzed +entry enemy_bari_die +entry enemy_ganondorf_orb_trail +entry enemy_phantom_reveal +entry enemy_phantom_lightning +entry enemy_ganondorf_charge +entry enemy_ganondorf_fly +entry enemy_witch_charge +entry enemy_phantom_painting_enter +entry enemy_ganondorf_orb_trail +entry enemy_ganondorf_lightning_hit +entry enemy_phantom_attack_unused +entry enemy_phantom_staff +entry enemy_phantom_eyes +entry enemy_phantom_die_roar +entry enemy_phantom_orb_dissipate +entry enemy_phantom_hurt +entry enemy_phantom_die +entry enemy_phantom_laugh +entry enemy_phantom_hurt_orb +entry enemy_phantom_shout +entry enemy_guay_hurt +entry enemy_ganondorf_charge_major +entry enemy_ganondorf_magic_fire +entry enemy_guay_chirp +entry enemy_guay_attack +entry enemy_moblin_walk +entry enemy_moblin_slide +entry enemy_moblin_attack_shout +entry enemy_moblin_grunt +entry enemy_moblin_spear_point +entry enemy_moblin_spear_relax +entry enemy_moblin_die +entry enemy_moblin_dash +entry enemy_octorok_rock_break +entry enemy_octorok_float +entry enemy_octorok_jump +entry enemy_tektite_land_water1 +entry enemy_octorok_dive +entry enemy_octorok_bubble +entry enemy_octorok_die +entry enemy_octorok_death_gasp +entry enemy_keese_fly +entry enemy_bubble_dash +entry enemy_bubble_cry +entry enemy_bubble_attack +entry enemy_bubble_flame_appear +entry enemy_bubble_flame_vanish +entry enemy_bubble_die +entry enemy_dodongo_flame +entry enemy_boss_volvagia_hole +entry enemy_boss_volvagia_roar +entry enemy_boss_gohma_hurt_eye +entry enemy_volvagia_fall +entry enemy_volvagia_paralyzed +entry enemy_boss_gohma_hurt +entry enemy_boss_volvagia_cry +entry enemy_boss_volvagia_rock +entry enemy_boss_volvagia_swipe +entry enemy_boss_gohma_die +entry enemy_boss_dodongo_fossilize +entry enemy_boss_dodongo_flame +entry enemy_biri_die +entry enemy_dodongo_jr_land +entry enemy_boss_morpha_water_move +entry enemy_tektite_turn_water +entry enemy_moblin_club_shockwave +entry enemy_moblin_club_strike +entry enemy_moblin_club_lift +entry enemy_bubble_hurt +entry enemy_redead_moan +entry enemy_redead_scream +entry enemy_redead_hurt +entry enemy_redead_die +entry enemy_redead_attack +entry enemy_spike_trap_roll +entry enemy_spike_trap_rock +entry enemy_guay_die +entry enemy_poe_laugh +entry enemy_poe_sister_cry +entry enemy_poe_sister_attack +entry enemy_poe_sister_laugh +entry enemy_boss_morpha_rise +entry enemy_boss_morpha_attack +entry enemy_boss_morpha_toss +entry enemy_boss_morpha_grab +entry enemy_boss_morpha_caught +entry enemy_boss_morpha_demo_move +entry enemy_boss_morpha_demo_bubble +entry enemy_tektite_jump_water +entry enemy_boss_morpha_die +entry enemy_boss_morpha_die_cry +entry enemy_boss_morpha_water_spin +entry enemy_witch_charge +entry enemy_goron_wake +entry enemy_goron_sit +entry enemy_unused +entry enemy_cucco_flap +entry enemy_deadhand_bite +entry enemy_deadhand_move +entry enemy_deadhand_grabbed +entry enemy_deadhand_grab +entry enemy_big_octo_paralyzed +entry enemy_big_octo_walk +entry enemy_big_octo_grunt +entry enemy_big_octo_hurt +entry enemy_big_octo_stop +entry enemy_big_octo_die +entry enemy_big_octo_die2 +entry enemy_phantom_lightning +entry enemy_boss_twinrova_appear +entry enemy_boss_twinrova_transform +entry enemy_boss_twinrova_fire_charge +entry enemy_boss_twinrova_fire_hit +entry enemy_boss_twinrova_charge +entry enemy_boss_twinrova_ice_beam +entry enemy_boss_twinrova_ice_charge +entry enemy_boss_twinrova_cast +entry enemy_boss_ganondorf_struck +entry enemy_boss_dodongo_demo_wall +entry enemy_boss_twinrova_hurt_cry_old +entry enemy_boss_twinrova_ice_reflected +entry enemy_boss_twinrova_fire_reflected +entry enemy_boss_ganondorf_struck +entry enemy_boss_twinrova_hit_beam_young +entry enemy_boss_twinrova_die_young +entry enemy_biggoron_blind +entry enemy_biggoron_happy +entry enemy_boss_twinrova_spirit_fly +entry enemy_boss_twinrova_fly +entry enemy_boss_twinrova_hover +entry enemy_poe_sister_attack +entry enemy_ganondorf_orb_trail +entry enemy_phantom_painting_enter +entry enemy_darunia_chest_pound +entry enemy_darunia_head_pat +entry enemy_owl_fly +entry enemy_goron_land +entry enemy_knuckle_walk +entry enemy_knuckle_attack +entry enemy_knuckle_clank +entry enemy_knuckle_stagger +entry enemy_knucle_armor_loss +entry enemy_knuckle_armor_rebound1 +entry enemy_knuckle_armor_rebound2 +entry enemy_knuckle_armor_rebound3 +entry enemy_floormaster_attack +entry enemy_floormaster_mini_walk +entry enemy_floormaster_mini_die +entry enemy_floormaster_mini_grow +entry enemy_floormaster_grow_done +entry enemy_floormaster_split +entry enemy_floormaster_mini_grab +entry enemy_floormaster_mini_land +entry enemy_knuckle_warcry +entry enemy_knuckle_snap +entry enemy_knuckle_armor_hurt +entry enemy_boss_ganondorf_struck +entry enemy_boss_barinade_pulse +entry enemy_boss_barinade_hurt +entry enemy_boss_barinade_weak_hurt +entry enemy_boss_barinade_die +entry enemy_boss_twinrova_hurt +entry enemy_boss_barinade_bari_attach +entry enemy_boss_barinade_beam +entry enemy_biri_shock +entry enemy_biri_die +entry enemy_boss_barinade_tentacle_break +entry enemy_ganondorf_lightning_hit +entry enemy_boss_dodongo_roll +entry enemy_shabom_bounce +entry enemy_shabom_pop +entry enemy_blob_wave +entry enemy_octorok_rock_break +entry enemy_stinger_hurt +entry enemy_stinger_die +entry enemy_stinger_submerge +entry enemy_stinger_glide +entry enemy_boss_bongo_drum_low +entry enemy_boss_bongo_drum_high +entry enemy_boss_bongo_clap +entry enemy_deadhand_grab +entry enemy_peahat_rise +entry enemy_peahat_fly +entry enemy_peahat_hurt +entry enemy_peahat_land +entry enemy_deadhand_grab +entry enemy_tentacle_wind_up +entry enemy_peahat_hurt +entry enemy_tentacle_die +entry enemy_larvae_walk +entry enemy_larvae_chirp +entry enemy_larvae_hurt +entry enemy_larvae_cry +entry enemy_larvae_die +entry enemy_larvae_egg_land +entry enemy_larvae_egg_break +entry enemy_boss_ganon_transform +entry enemy_boss_bongo_hand_wave +entry enemy_wallmaster_grab +entry enemy_goron_land +entry enemy_boss_bongo_hand_attack +entry enemy_boss_bongo_hand_shake +entry enemy_boss_bongo_hurt +entry enemy_boss_bongo_hand_hurt +entry enemy_boss_bongo_vanish +entry enemy_ganondorf_charge_major +entry enemy_boss_barinade_beam +entry enemy_boss_bongo_paralyze +entry enemy_boss_bongo_die +entry enemy_beamos_idle +entry enemy_beamos_beam +entry enemy_beamos_ground_hit +entry enemy_beamos_charging +entry enemy_torch_slug_crawl +entry enemy_torch_slug_target +entry enemy_tektite_flip +entry enemy_torch_slug_hurt +entry enemy_torch_slug_die +entry enemy_tile_fly +entry enemy_firedancer_hurt +entry enemy_boss_twinrova_fly +entry enemy_firedancer_kick +entry enemy_moblin_club_shockwave +entry enemy_firedancer_spin +entry enemy_firehead_run +entry enemy_firehead_hurt +entry enemy_firedancer_laugh +entry enemy_deku_baba_slide +entry enemy_boss_volvagia_hole +entry enemy_peahat_jr_fly +entry enemy_keese_die +entry enemy_leever_emerge +entry enemy_shop_scrub_burrow +entry enemy_boss_gohma_hurt +entry enemy_leever_die +entry enemy_blob_wave +entry enemy_firehead_cry +entry enemy_boss_bongo_dissipate +entry enemy_boss_bongo_charge +entry enemy_boss_bongo_chant +entry enemy_boss_ganon_roar +entry enemy_torch_slug_crawl +entry enemy_boss_morpha_grab +entry enemy_boss_dodongo_swallow +entry enemy_boss_gohma_eyeroll +entry enemy_scrub_spit +entry enemy_boss_gohma_hurt +entry enemy_like_like_die +entry enemy_boss_ganon_attack +entry enemy_gerudo_attack +entry enemy_gerudo_hurt +entry enemy_gerudo_defeat +entry enemy_boss_ganon_hurt +entry enemy_dodongo_flame +entry enemy_anubis_fire_hit +entry enemy_boss_ganon_penultimate_hit +entry enemy_anubis_die +entry enemy_wolfos_walk +entry enemy_boss_ganon_die +entry enemy_stinger_attack +entry enemy_stinger_cry +entry enemy_boss_twinrova_ice_beam +entry enemy_freezard_hurt +entry enemy_freezard_die +entry enemy_deadhand_laugh +entry enemy_deadhand_burrow +entry enemy_deadhand_hurt +entry enemy_big_baba_die +entry enemy_deadhand_die +entry enemy_knuckle_stump_break +entry enemy_knuckle_pillar_break +entry enemy_knuckle_axe_stuck +entry enemy_boss_ganon_paralyze +entry enemy_boss_vocals +entry enemy_boss_vocals +entry enemy_boss_vocals +entry enemy_boss_vocals +entry enemy_boss_vocals +entry enemy_boss_vocals +entry enemy_boss_vocals +entry enemy_boss_vocals +entry enemy_boss_vocals +entry enemy_boss_vocals +entry enemy_boss_vocals +entry enemy_boss_vocals +entry enemy_boss_vocals +entry enemy_boss_vocals +entry enemy_boss_vocals +entry enemy_boss_vocals +entry enemy_boss_vocals +entry enemy_boss_vocals +entry enemy_boss_vocals +entry enemy_boss_vocals +entry enemy_boss_vocals +entry enemy_boss_vocals +entry enemy_boss_vocals +entry enemy_boss_vocals +entry enemy_boss_vocals +entry enemy_boss_vocals +entry enemy_boss_vocals +entry enemy_boss_vocals +entry enemy_boss_vocals +entry enemy_boss_vocals +entry enemy_boss_vocals +entry enemy_boss_vocals +entry enemy_boss_vocals +entry enemy_boss_vocals +entry enemy_boss_vocals +entry enemy_boss_vocals +entry enemy_boss_vocals +entry enemy_boss_vocals +entry enemy_boss_vocals +entry enemy_goron_land +entry enemy_deadhand_burrow +entry enemy_boss_ganon_growl +entry enemy_gold_skull_spin +entry enemy_blob_wave +entry enemy_armos_hop +entry enemy_knuckle_stump_break +entry enemy_armos_hop +entry enemy_boss_ganon_sword_clank +entry enemy_deadhand_grab +entry enemy_skulltula_creak +entry enemy_floormaster_grow_done +entry enemy_dodongo_jr_land +entry enemy_stalfos_walk +entry enemy_dodongo_jr_land +entry enemy_stalfos_walk +entry enemy_boss_twinrova_bicker +entry enemy_big_poe_caught_soul +entry enemy_bug_burrow +entry enemy_gold_skull_cry +entry enemy_goron_child_cry +entry enemy_boss_gohma_hurt +entry enemy_tektite_land_water1 +entry enemy_deadhand_burrow +entry enemy_goron_land +entry enemy_bug_walk +entry enemy_boss_twinrova_ice_beam +entry enemy_skulltula_quiver + +.channel enemy_dodongo_walk +instr FONT01_INSTR_GUNSHOT +env envelope_68DC +ldlayer 0, layer_354D +end + +.layer layer_354D +portamento 0x81, 34, 80 +notedv PITCH_C3, 0x1E, 100 +end + +.channel enemy_dodongo_breathe +ldlayer 0, layer_3559 +end + +.layer layer_3559 +instr FONT01_INSTR_DODONGO_ROAR +notedv PITCH_D4, 0x50, 100 +end + +.channel enemy_dodongo_flame +instr 2 +ldlayer 0, layer_3565 +end + +.layer layer_3565 +notedv PITCH_F2, 30000, 100 +rjump layer_3565 + +.channel enemy_dodongo_hurt +instr FONT01_INSTR_DODONGO_ROAR +ldlayer 0, layer_3574 +ldlayer 1, layer_4829 +end + +.layer layer_3574 +portamento 0x81, 36, 255 +notedv PITCH_E4, 0xA, 100 +portamento 0x81, 44, 255 +notedv PITCH_B3, 0x24, 100 +end + +.channel enemy_dodongo_die +instr FONT01_INSTR_DODONGO_ROAR +ldlayer 0, layer_358F +ldlayer 1, layer_3591 +ldlayer 2, layer_4829 +end + +.layer layer_358F +transpose -6 + +.layer layer_3591 +portamento 0x81, 38, 255 +notedv PITCH_GF4, 0xA, 100 +portamento 0x81, 46, 255 +notedv PITCH_DF4, 0x5A, 100 +end + +.channel enemy_boss_dodongo_exhale +instr FONT01_INSTR_DODONGO_ROAR +env envelope_683C +ldlayer 0, layer_35AC +ldlayer 1, layer_35AE +end + +.layer layer_35AC +transpose -12 + +.layer layer_35AE +portamento 1, 34, 20 +notedv PITCH_B3, 0x5A, 100 +end + +.channel enemy_boss_dodongo_walk +instr FONT01_INSTR_GUNSHOT +ldlayer 0, layer_35CA +ldlayer 1, layer_35C6 +ldlayer 2, layer_35C2 +end + +.layer layer_35C2 +notedv PITCH_B3, 0x50, 100 +end + +.layer layer_35C6 +notedv PITCH_D3, 0x50, 100 +end + +.layer layer_35CA +notedv PITCH_F2, 0x50, 100 +end + +.channel enemy_boss_dodongo_flame +instr 2 +ldlayer 0, layer_35D9 +ldlayer 1, layer_35D7 +end + +.layer layer_35D7 +transpose -12 + +.layer layer_35D9 +notedv PITCH_G3, 30000, 100 +rjump layer_35D9 + +.channel enemy_larvae_egg_break +instr FONT01_INSTR_EGG_CRACK +ldlayer 0, layer_35E5 +end + +.layer layer_35E5 +notedv PITCH_F3, 0x50, 100 +end + +.channel enemy_boss_gohma_fall +instr FONT01_INSTR_SMASH +ldlayer 0, layer_35F5 +ldlayer 1, layer_35F7 +ldlayer 2, layer_3606 +end + +.layer layer_35F5 +transpose -8 + +.layer layer_35F7 +env envelope_69DC, 240 +portamento 0x81, 34, 64 +notedv PITCH_C3, 0x32, 100 +notedv PITCH_C1, 0x5A, 100 +end + +.layer layer_3606 +env envelope_69DC, 240 +portamento 0x81, 38, 64 +notedv PITCH_E3, 0x32, 100 +end + +.channel enemy_goron_land +instr FONT01_INSTR_SMASH +ldlayer 0, layer_361B +ldlayer 1, layer_361D +end + +.layer layer_361B +transpose -8 + +.layer layer_361D +env envelope_69DC, 250 +portamento 0x81, 34, 64 +notedv PITCH_C3, 0x62, 100 +end + +.channel enemy_lizalfos_land_flat +instr FONT01_INSTR_SMASH +ldlayer 0, layer_3631 +gain 18 +end + +.layer layer_3631 +env envelope_690C, 250 +portamento 0x81, 29, 150 +notedv PITCH_C3, 0x8, 100 +env envelope_68EC, 250 +portamento 0x81, 27, 150 +notedv PITCH_F2, 0x1E, 100 +end + +.channel enemy_dodongo_jr_land +ldlayer 0, layer_364C +end + +.layer layer_364C +instr FONT01_INSTR_SMASH +env envelope_68DC, 250 +portamento 0x81, 36, 64 +notedv PITCH_D3, 0x1E, 100 +end + +.channel enemy_boss_gohma_walk +instr FONT01_INSTR_SMASH +env envelope_68EC +ldlayer 0, layer_3665 +gain 16 +end + +.layer layer_3665 +portamento 0x81, 37, 64 +notedv PITCH_EF3, 0x28, 100 +end + +.channel enemy_boss_gohma_climb +instr FONT01_INSTR_TEKTITE_ROTATE +ldlayer 1, layer_3676 +ldlayer 0, layer_3678 +end + +.layer layer_3676 +transpose 1 + +.layer layer_3678 +portamento 0x81, 19, 64 +notedv PITCH_G2, 0x14, 100 +end + +.channel enemy_boss_gohma_birth +instr FONT01_INSTR_MONSTER_ROAR +env envelope_698C +ldlayer 0, layer_368B +gain 18 +end + +.layer layer_368B +legato +portamento 0x85, 20, 255 +notedv PITCH_GF2, 0x28, 100 +notedv PITCH_F2, 0x55, 100 +end + +.channel enemy_larvae_walk +instr FONT01_INSTR_GRASS_RUSTLE +ldlayer 0, layer_369D +end + +.layer layer_369D +portamento 0x81, 31, 255 +notedv PITCH_C3, 0x5, 100 +end + +.channel enemy_larvae_chirp +instr FONT01_INSTR_MECH +ldlayer 0, layer_36AB +end + +.layer layer_36AB +portamento 0x81, 48, 255 +notedv PITCH_GF4, 0x1E, 100 +end + +.channel enemy_larvae_hurt +ldlayer 0, layer_4829 +ldlayer 1, layer_36BD +ldlayer 2, layer_36C1 +end + +.layer layer_36BD +instr FONT01_INSTR_MECH +rjump layer_36C3 + +.layer layer_36C1 +instr FONT01_INSTR_MONSTER_ROAR +.layer layer_36C3 +portamento 0x81, 51, 255 +notedv PITCH_B5, 0xA, 100 +portamento 0x81, 60, 255 +notedv PITCH_E5, 0x12, 100 +end + +.channel enemy_larvae_cry +ldlayer 0, layer_36D6 +end + +.layer layer_36D6 +instr FONT01_INSTR_MECH +portamento 0x81, 51, 255 +notedv PITCH_F5, 0xA, 100 +portamento 0x81, 53, 255 +notedv PITCH_G5, 0xA, 100 +transpose 4 +portamento 0x81, 55, 255 +notedv PITCH_B5, 0xA, 100 +transpose 6 +portamento 0x81, 51, 255 +notedv PITCH_B5, 0x14, 100 +end + +.channel enemy_larvae_die +ldlayer 0, layer_3700 +ldlayer 1, layer_4829 +end + +.layer layer_3700 +instr FONT01_INSTR_MECH +portamento 0x81, 56, 255 +notedv PITCH_C5, 0x5, 100 +portamento 0x81, 54, 255 +notedv PITCH_BF4, 0xA, 100 +portamento 0x81, 51, 255 +notedv PITCH_AF4, 0xA, 100 +portamento 0x81, 47, 255 +notedv PITCH_DF4, 0x14, 100 +end + +.channel enemy_boss_gohma_walk_ceiling +instr FONT01_INSTR_GRASS_RUSTLE +ldlayer 0, layer_3728 +ldlayer 1, layer_372C +end + +.layer layer_3728 +notedv PITCH_E3, 0x50, 100 +end + +.layer layer_372C +ldelay 0xF +notedv PITCH_C4, 0x50, 100 +end + +.channel enemy_boss_gohma_hurt_eye +ldlayer 0, layer_374D +ldlayer 1, layer_3739 +end + +.layer layer_3739 +instr FONT01_INSTR_DINO_ROAR +legato +portamento 0x85, 39, 255 +notedv PITCH_G4, 0x14, 80 +notedv PITCH_C4, 0x14, 80 +notedv PITCH_E4, 0x14, 80 +notedv PITCH_A3, 0x14, 80 +end + +.layer layer_374D +instr FONT01_INSTR_MONSTER_ROAR +legato +portamento 0x85, 39, 255 +notedv PITCH_G4, 0xA, 100 +notedv PITCH_C4, 0xA, 100 +notedv PITCH_G4, 0xA, 100 +notedv PITCH_C4, 0xA, 100 +notedv PITCH_G4, 0xA, 100 +notedv PITCH_C4, 0x5, 100 +end + +.channel enemy_larvae_egg_land +instr FONT01_INSTR_SMASH +ldlayer 0, layer_376F +gain 18 +end + +.layer layer_376F +legato +env envelope_68FC, 255 +portamento 0x85, 25, 230 +notedv PITCH_EF3, 0x5, 100 +notedv PITCH_BF2, 0x5, 100 +nolegato +ldelay 0x5 +legato +env envelope_68FC, 255 +portamento 0x85, 25, 220 +notedv PITCH_EF3, 0x5, 100 +notedv PITCH_BF2, 0xA, 100 +end + +.channel chan_unused_3791 +instr FONT01_INSTR_POE_DISAPPEAR +ldlayer 0, layer_3797 +end + +.layer layer_3797 +notedv PITCH_D4, 0x46, 100 +end + +.channel enemy_keese_attack +instr FONT01_INSTR_KEESE +ldlayer 0, layer_37A3 +gain 50 +end + +.layer layer_37A3 +portamento 0x81, 37, 100 +notedv PITCH_EF4, 0x32, 100 +end + +.channel enemy_keese_fly +ldlayer 0, layer_37AF +end + +.layer layer_37AF +instr FONT01_INSTR_OWL_FLAP +portamento 0x81, 36, 255 +notedv PITCH_E4, 0xA, 100 +portamento 0x81, 42, 255 +notedv PITCH_DF4, 0x6, 100 +end + +.channel enemy_dodongo_jr_yell +ldlayer 0, layer_37C7 +ldlayer 1, layer_37D3 +end + +.layer layer_37C7 +instr FONT01_INSTR_DODONGO_ROAR +ldelay 0xA +portamento 0x81, 48, 64 +notedv PITCH_D5, 0x28, 100 +end + +.layer layer_37D3 +instr FONT01_INSTR_GUNSHOT +env envelope_686C, 240 +transpose 6 +portamento 0x81, 26, 100 +notedv PITCH_B5, 0x32, 100 +end + +.channel enemy_dodongo_jr_die +ldlayer 0, layer_37EA +ldlayer 1, layer_4829 +end + +.layer layer_37EA +instr FONT01_INSTR_DODONGO_ROAR +portamento 0x81, 48, 255 +notedv PITCH_D5, 0xA, 100 +portamento 0x81, 55, 255 +notedv PITCH_F4, 0x48, 100 +end + +.channel enemy_boss_gohma_roar +ldlayer 0, layer_3809 +ldlayer 1, layer_3802 +end + +.layer layer_3802 +instr FONT01_INSTR_MONSTER_ROAR +notedv PITCH_E4, 0x96, 70 +end + +.layer layer_3809 +instr FONT01_INSTR_DINO_ROAR +legato +portamento 0x81, 39, 255 +notedv PITCH_D4, 0xA, 100 +portamento 0x81, 41, 255 +notedv PITCH_F4, 0xC8, 100 +end + +.channel enemy_boss_gohma_hurt +ldlayer 0, layer_3838 +ldlayer 1, layer_3826 +ldlayer 2, layer_4829 +end + +.layer layer_3826 +instr FONT01_INSTR_DINO_ROAR +legato +portamento 0x81, 42, 64 +notedv PITCH_BF4, 0x14, 80 +portamento 0x81, 47, 255 +notedv PITCH_AF3, 0x24, 80 +end + +.layer layer_3838 +instr FONT01_INSTR_MONSTER_ROAR +portamento 0x81, 39, 255 +notedv PITCH_G4, 0xF, 100 +portamento 0x81, 44, 255 +notedv PITCH_B3, 0x24, 100 +end + +.channel enemy_boss_gohma_growl +instr FONT01_INSTR_EGG_CRACK +ldlayer 0, layer_3854 +ldlayer 1, layer_3852 +end + +.layer layer_3852 +transpose 2 + +.layer layer_3854 +notedv PITCH_C2, 0x64, 100 +end + +.channel enemy_dodongo_jr_walk +ldlayer 0, layer_385C +end + +.layer layer_385C +instr FONT01_INSTR_TEKTITE_ROTATE +notedv PITCH_D2, 0x1E, 70 +end + +.channel enemy_dodongo_jr_burrow +ldlayer 0, layer_3866 +end + +.layer layer_3866 +instr FONT01_INSTR_TEKTITE_ROTATE +notedv PITCH_BF2, 0x19, 100 +notedv PITCH_AF2, 0x14, 100 +notedv PITCH_BF2, 0xF, 100 +notedv PITCH_AF2, 0xF, 100 +notedv PITCH_BF2, 0xA, 100 +notedv PITCH_AF2, 0xF, 100 +notedv PITCH_BF2, 0xF, 70 +.layer layer_387D +notedv PITCH_AF2, 0xF, 70 +notedv PITCH_BF2, 0xF, 70 +notedv PITCH_AF2, 0xF, 70 +notedv PITCH_BF2, 0xA, 60 +notedv PITCH_AF2, 0xA, 60 +end + +.channel enemy_bug_burrow +ldlayer 0, layer_3891 +end + +.layer layer_3891 +instr FONT01_INSTR_TEKTITE_ROTATE +rjump layer_387D + +.channel enemy_bug_walk +ldlayer 0, layer_3899 +end + +.layer layer_3899 +instr FONT01_INSTR_TEKTITE_ROTATE +notedv PITCH_AF2, 0x8, 40 +notedv PITCH_G2, 0x8, 40 +end + +.channel enemy_dodongo_jr_emerge +ldlayer 0, layer_38A6 +end + +.layer layer_38A6 +instr FONT01_INSTR_TEKTITE_ROTATE +notedv PITCH_GF2, 0x19, 100 +notedv PITCH_AF2, 0x14, 100 +end + +.channel enemy_shop_scrub_burrow +ldlayer 0, layer_38B6 +ldlayer 1, layer_3866 +end + +.layer layer_38B6 +transpose -5 +rjump layer_3866 + +.channel enemy_leever_emerge +ldlayer 0, layer_38C1 +ldlayer 1, layer_38A6 +end + +.layer layer_38C1 +transpose -2 +ldelay 0x3 +rjump layer_38A6 + +.channel enemy_dodongo_jr_eat +instr FONT01_INSTR_GULP_SPEAR +ldlayer 0, layer_38CD +end + +.layer layer_38CD +notedv PITCH_C3, 0x30, 100 +end + +.channel enemy_stalfos_walk +instr FONT01_INSTR_SMASH +ldlayer 0, layer_38D7 +end + +.layer layer_38D7 +portamento 0x81, 35, 64 +notedv PITCH_DF3, 0xC, 64 +end + +.channel enemy_stalfos_laugh +ldlayer 0, layer_38E5 +gain 16 +end + +.layer layer_38E5 +instr FONT01_INSTR_PHANTOM_LAUGH_0 +notedv PITCH_C4, 0x8C, 100 +end + +.channel enemy_lizalfos_hurt +ldlayer 0, layer_38F6 +ldlayer 1, layer_3907 +ldlayer 2, layer_4829 +end + +.layer layer_38F6 +instr FONT01_INSTR_LIZALFOS +portamento 0x81, 33, 255 +notedv PITCH_DF4, 0xF, 100 +portamento 0x81, 38, 255 +notedv PITCH_AF2, 0x28, 100 +end + +.layer layer_3907 +instr FONT01_INSTR_MOBLIN_GROWL +notedv PITCH_C5, 0x5, 100 +notedv PITCH_B4, 0x5, 100 +notedv PITCH_A4, 0x5, 100 +notedv PITCH_E4, 0x5, 100 +end + +.channel enemy_lizalfos_laugh +ldlayer 0, layer_391A +end + +.layer layer_391A +instr FONT01_INSTR_LAUGHTER +portamento 0x81, 44, 255 +notedv PITCH_C4, 0x14, 100 +end + +.channel enemy_lizalfos_die +ldlayer 0, layer_392E +ldlayer 1, layer_393F +ldlayer 2, layer_4829 +end + +.layer layer_392E +instr FONT01_INSTR_LIZALFOS +portamento 0x81, 35, 255 +notedv PITCH_E3, 0xF, 100 +portamento 0x81, 31, 255 +notedv PITCH_C3, 0x1E, 100 +end + +.layer layer_393F +instr FONT01_INSTR_MOBLIN_GROWL +notedv PITCH_AF5, 0x5, 100 +notedv PITCH_F5, 0x5, 100 +notedv PITCH_DF5, 0x5, 100 +notedv PITCH_BF4, 0x5, 100 +end + +.channel enemy_stalfos_hurt +ldlayer 0, layer_3958 +.channel chan_3951 +ldlayer 1, layer_3962 +ldlayer 2, layer_4829 +end + +.layer layer_3958 +instr FONT01_INSTR_PHANTOM_MOAN +portamento 0x81, 47, 100 +notedv PITCH_G4, 0x50, 100 +end + +.layer layer_3962 +instr FONT01_INSTR_POT_BREAK +notedv PITCH_G3, 0x5, 100 +notedv PITCH_G3, 0x5, 100 +end + +.channel enemy_stalkid_hurt +ldlayer 0, layer_3970 +rjump chan_3951 + +.layer layer_3970 +transpose 19 +rjump layer_3958 + +.channel enemy_stalfos_die +ldlayer 0, layer_3984 +.channel chan_3977 +ldlayer 1, layer_3997 +ldlayer 2, layer_4829 +gain 20 +vibfreq 50 +vibdepth 10 +end + +.layer layer_3984 +instr FONT01_INSTR_PHANTOM_MOAN +legato +portamento 0x85, 43, 200 +notedv PITCH_AF4, 0x1E, 100 +notedv PITCH_A3, 0x8C, 100 +notedv PITCH_E4, 0xC8, 100 +end + +.layer layer_3997 +instr FONT01_INSTR_POT_BREAK +notedv PITCH_G3, 0x5, 100 +notedv PITCH_G3, 0xF, 100 +end + +.channel enemy_stalkid_die +ldlayer 0, layer_39A5 +rjump chan_3977 + +.layer layer_39A5 +transpose 14 +rjump layer_3984 + +.channel enemy_firehead_cry +ldlayer 0, layer_39A5 +end + +.channel enemy_lizalfos_walk +ldlayer 0, layer_39B1 +end + +.layer layer_39B1 +instr FONT01_INSTR_LIZALFOS +transpose 48 +notedv PITCH_DF4, 0xA, 80 +end + +.channel enemy_lizalfos_land +ldlayer 0, layer_39BD +end + +.layer layer_39BD +instr FONT01_INSTR_LIZALFOS +transpose 48 +notedv PITCH_E4, 0xA, 80 +notedv PITCH_D4, 0xA, 80 +end + +.channel enemy_lizalfos_jump +ldlayer 0, layer_39DD +ldlayer 1, layer_39D2 +ldlayer 2, layer_39ED +end + +.layer layer_39D2 +instr FONT01_INSTR_LIZALFOS +transpose 48 +notedv PITCH_E4, 0xA, 100 +notedv PITCH_GF4, 0xA, 100 +end + +.layer layer_39DD +instr FONT01_INSTR_GUNSHOT +env envelope_686C, 240 +transpose 4 +portamento 0x81, 26, 50 +notedv PITCH_B5, 0x50, 100 +end + +.layer layer_39ED +instr FONT01_INSTR_MOBLIN_GROWL +ldelay 0xA +notedv PITCH_EF4, 0x5, 100 +notedv PITCH_D4, 0x5, 100 +notedv PITCH_C4, 0x5, 100 +notedv PITCH_C4, 0x5, 100 +end + +.channel enemy_armos_hop +instr FONT01_INSTR_SMASH +ldlayer 0, layer_3A04 +end + +.layer layer_3A04 +portamento 0x81, 39, 200 +notedv PITCH_A3, 0x14, 100 +end + +.channel enemy_armos_awaken +instr FONT01_INSTR_SMASH +env envelope_690C +ldlayer 1, layer_3A18 +ldlayer 0, layer_3A2E +end + +.layer layer_3A18 +notedv PITCH_E2, 0xA, 100 +notedv PITCH_GF2, 0xA, 100 +notedv PITCH_E2, 0xA, 100 +notedv PITCH_GF2, 0xA, 100 +notedv PITCH_E2, 0xA, 100 +notedv PITCH_GF2, 0xA, 100 +notedv PITCH_E2, 0xA, 100 +end + +.layer layer_3A2E +instr FONT01_INSTR_PHANTOM_WAIL +env envelope_699C, 250 +legato +portamento 0x85, 23, 255 +notedv PITCH_C4, 0x1E, 100 +notedv PITCH_F3, 0x52, 100 +end + +.channel enemy_armos_die +ldlayer 0, layer_3A47 +ldlayer 1, layer_4829 +end + +.layer layer_3A47 +instr FONT01_INSTR_PHANTOM_WAIL +env envelope_699C, 240 +legato +portamento 0x85, 37, 200 +notedv PITCH_GF4, 0x1E, 100 +notedv PITCH_GF3, 0x64, 100 +end + +.channel enemy_armos_roar +instr FONT01_INSTR_PHANTOM_WAIL +env envelope_699C +gain 19 +ldlayer 0, layer_3A64 +end + +.layer layer_3A64 +legato +portamento 0x85, 23, 255 +notedv PITCH_C4, 0x1E, 100 +notedv PITCH_F3, 0x52, 100 +end + +.channel enemy_stalfos_attack +ldlayer 0, layer_3A79 +ldlayer 1, layer_3A87 +gain 20 +end + +.layer layer_3A79 +instr FONT01_INSTR_STALFOS_ATTACK +legato +portamento 0x85, 30, 30 +notedv PITCH_BF4, 0x14, 100 +notedv PITCH_A4, 0x14, 100 +end + +.layer layer_3A87 +instr FONT01_INSTR_GERUDO_ATTACK +env envelope_682C, 240 +ldelay 0xA +notedv PITCH_B3, 0x1E, 100 +end + +.channel enemy_armos_hurt +ldlayer 0, layer_3A9A +ldlayer 1, layer_4829 +end + +.layer layer_3A9A +instr FONT01_INSTR_PHANTOM_WAIL +legato +portamento 0x85, 39, 100 +notedv PITCH_F4, 0x1E, 100 +notedv PITCH_C4, 0x1E, 100 +end + +.channel enemy_boss_dodongo_demo_wall +instr FONT01_INSTR_GUNSHOT +ldlayer 0, layer_3AB4 +ldlayer 1, layer_3ABF +ldlayer 2, layer_3ACA +end + +.layer layer_3AB4 +notedv PITCH_GF3, 0x14, 100 +env envelope_688C, 240 +notedv PITCH_AF2, 0x64, 100 +end + +.layer layer_3ABF +notedv PITCH_BF3, 0x14, 100 +env envelope_688C, 240 +notedv PITCH_C3, 0x64, 100 +end + +.layer layer_3ACA +notedv PITCH_DF4, 0x14, 100 +env envelope_688C, 240 +notedv PITCH_EF3, 0x64, 100 +end + +.channel enemy_boss_dodongo_wall_hit +instr FONT01_INSTR_GUNSHOT +ldlayer 0, layer_3ADE +ldlayer 1, layer_3AE9 +end + +.layer layer_3ADE +notedv PITCH_GF3, 0x14, 100 +env envelope_688C, 240 +notedv PITCH_AF2, 0x32, 100 +end + +.layer layer_3AE9 +notedv PITCH_B3, 0x14, 100 +env envelope_688C, 240 +notedv PITCH_DF3, 0x32, 100 +end + +.channel enemy_boss_dodongo_roll +ldlayer 0, layer_3B01 +ldlayer 1, layer_3AFF +vibfreq 20 +vibdepth 100 +end + +.layer layer_3AFF +transpose 12 + +.layer layer_3B01 +instr FONT01_INSTR_BOULDER +.layer layer_3B03 +notedv PITCH_C4, 30000, 100 +rjump layer_3B03 + +.channel enemy_boss_dodongo_inhale +instr FONT01_INSTR_DINO_INHALE +ldlayer 0, layer_3B14 +ldlayer 1, layer_3B12 +end + +.layer layer_3B12 +transpose -4 + +.layer layer_3B14 +legato +portamento 0x81, 27, 255 +notedv PITCH_F3, 0xAA, 100 +.layer layer_3B1D +notedv PITCH_F3, 30000, 100 +rjump layer_3B1D + +.channel enemy_boss_dodongo_swallow +instr FONT01_INSTR_GULP_SPEAR +ldlayer 0, layer_3B2E +ldlayer 1, layer_3B30 +gain 24 +end + +.layer layer_3B2E +transpose -2 + +.layer layer_3B30 +notedv PITCH_C3, 0x46, 100 +end + +.channel enemy_boss_dodongo_paralyzed +instr FONT01_INSTR_DODONGO_ROAR +env envelope_683C +ldlayer 0, layer_3B40 +ldlayer 1, layer_3B42 +end + +.layer layer_3B40 +transpose -4 + +.layer layer_3B42 +legato +portamento 0x85, 15, 255 +notedv PITCH_D2, 0x32, 100 +notedv PITCH_B1, 0x32, 100 +nolegato +rjump layer_3B42 + +.channel enemy_dodongo_inhale +instr FONT01_INSTR_DINO_INHALE +ldlayer 0, layer_3B56 +end + +.layer layer_3B56 +notedv PITCH_E3, 30000, 100 +rjump layer_3B56 + +.channel enemy_big_baba_chomp +instr FONT01_INSTR_BABA_ATTACK +ldlayer 0, layer_3B62 +end + +.layer layer_3B62 +notedv PITCH_F3, 0x1E, 100 +end + +.channel enemy_big_baba_attack +ldlayer 0, layer_3B6A +end + +.layer layer_3B6A +instr FONT01_INSTR_BABA_LUNGE +transpose 48 +portamento 0x81, 39, 200 +notedv PITCH_E4, 0x32, 100 +end + +.channel enemy_big_baba_hurt +ldlayer 0, layer_3B7D +ldlayer 1, layer_4829 +end + +.layer layer_3B7D +instr FONT01_INSTR_GUAY_HURT +portamento 0x81, 44, 255 +notedv PITCH_C5, 0xA, 100 +portamento 0x81, 53, 255 +notedv PITCH_F4, 0x1E, 100 +end + +.channel enemy_big_baba_die +ldlayer 0, layer_3B99 +ldlayer 1, layer_4829 +vibfreq 100 +vibdepth 127 +end + +.layer layer_3B99 +instr FONT01_INSTR_MONSTER_ROAR +env envelope_69AC, 255 +legato +portamento 0x85, 31, 255 +notedv PITCH_C4, 0x1E, 100 +notedv PITCH_C3, 0x78, 100 +end + +.channel enemy_shell_die +ldlayer 0, layer_3BB9 +ldlayer 1, layer_4BA9 +ldlayer 2, layer_4829 +vibfreq 48 +vibdepth 128 +end + +.layer layer_3BB9 +transpose 3 +rjump layer_3B99 + +.channel enemy_deku_baba_chomp +instr FONT01_INSTR_BABA_ATTACK +ldlayer 0, layer_3BC3 +end + +.layer layer_3BC3 +notedv PITCH_F4, 0xF, 100 +end + +.channel enemy_deku_baba_attack +ldlayer 0, layer_3BCB +end + +.layer layer_3BCB +instr FONT01_INSTR_BABA_LUNGE +transpose 48 +portamento 0x81, 48, 255 +notedv PITCH_C5, 0x1E, 100 +end + +.channel enemy_deku_baba_die +instr FONT01_INSTR_MONSTER_ROAR +env envelope_684C +ldlayer 0, layer_3BE7 +ldlayer 1, layer_4829 +vibfreq 100 +vibdepth 127 +end + +.layer layer_3BE7 +legato +portamento 0x85, 49, 200 +notedv PITCH_GF5, 0x1E, 100 +notedv PITCH_GF4, 0x32, 100 +end + +.channel enemy_deku_baba_slide +ldlayer 0, layer_3BFC +instr FONT01_INSTR_TEKTITE_ROTATE +env envelope_68BC +end + +.layer layer_3BFC +portamento 0x81, 13, 255 +notedv PITCH_G1, 0x38, 80 +end + +.channel enemy_keese_die +ldlayer 0, layer_3C0B +ldlayer 1, layer_4829 +end + +.layer layer_3C0B +instr FONT01_INSTR_GUAY_HURT +portamento 0x81, 44, 255 +notedv PITCH_C5, 0xA, 100 +portamento 0x81, 53, 255 +notedv PITCH_F4, 0x1E, 100 +end + +.channel enemy_tailpasaran_fly +instr FONT01_INSTR_BABA_LUNGE +ldlayer 0, layer_3C26 +vibfreq 64 +vibdepth 128 +end + +.layer layer_3C26 +notedv PITCH_BF2, 30000, 80 +rjump layer_3C26 + +.channel enemy_tailpasaran_cry +instr FONT01_INSTR_GRASS_RUSTLE +ldlayer 0, layer_3C32 +end + +.layer layer_3C32 +portamento 0x81, 14, 60 +notedv PITCH_E2, 0x32, 100 +end + +.channel enemy_tailpasaran_die +ldlayer 0, layer_3C45 +ldlayer 1, layer_4829 +vibfreq 112 +vibdepth 112 +end + +.layer layer_3C45 +instr FONT01_INSTR_GUAY_HURT +portamento 0x81, 35, 96 +notedv PITCH_C5, 0x14, 100 +portamento 0x81, 44, 207 +notedv PITCH_C4, 0x30, 100 +end + +.channel enemy_skulltula_climb +instr FONT01_INSTR_GRASS_RUSTLE +ldlayer 0, layer_3C5F +ldlayer 1, layer_3C67 +end + +.layer layer_3C5F +portamento 0x81, 39, 100 +notedv PITCH_E4, 0x32, 100 +end + +.layer layer_3C67 +ldelay 0x5 +portamento 0x81, 37, 100 +notedv PITCH_D4, 0x32, 100 +end + +.channel enemy_skulltula_drop +instr FONT01_INSTR_GRASS_RUSTLE +ldlayer 0, layer_3C7A +ldlayer 1, layer_3C82 +end + +.layer layer_3C7A +portamento 0x81, 43, 100 +notedv PITCH_C4, 0x32, 100 +end + +.layer layer_3C82 +ldelay 0x5 +portamento 0x81, 41, 100 +notedv PITCH_BF3, 0x32, 100 +end + +.channel enemy_skulltula_quiver +instr FONT01_INSTR_LAUGHTER +env envelope_699C +ldlayer 0, layer_3C9B +gain 16 +vibfreq 100 +vibdepth 127 +end + +.layer layer_3C9B +notedv PITCH_F1, 0x64, 100 +end + +.channel enemy_tektite_turn_ground +ldlayer 0, layer_3CA3 +end + +.layer layer_3CA3 +instr FONT01_INSTR_TEKTITE_ROTATE +notedv PITCH_C4, 0xA, 70 +end + +.channel enemy_poe_attack_charge +ldlayer 0, layer_3CB0 +ldlayer 1, layer_3CB6 +end + +.layer layer_3CB0 +instr FONT01_INSTR_OWL_FLAP +notedv PITCH_F3, 0x19, 100 +end + +.layer layer_3CB6 +instr FONT01_INSTR_POT_BREAK +notedv PITCH_F3, 0xA, 30 +end + +.channel enemy_poe_float +instr FONT01_INSTR_POE_DISAPPEAR +env envelope_69AC +ldlayer 0, layer_3CC9 +vibfreq 20 +vibdepth 127 +end + +.layer layer_3CC9 +notedv PITCH_F3, 0x87, 100 +rjump layer_3CC9 + +.channel enemy_poe_retreat +instr FONT01_INSTR_POE_DISAPPEAR +ldlayer 0, layer_3CD9 +vibfreq 60 +vibdepth 100 +end + +.layer layer_3CD9 +notedv PITCH_E4, 0x32, 100 +ldelay 0xA +rjump layer_3CD9 + +.channel enemy_poe_vanish +instr FONT01_INSTR_POE_DISAPPEAR +env envelope_69BC +ldlayer 0, layer_3CED +vibfreq 100 +vibdepth 100 +end + +.layer layer_3CED +portamento 0x81, 43, 255 +notedv PITCH_C2, 0x96, 100 +end + +.channel enemy_poe_appear +instr FONT01_INSTR_POE_DISAPPEAR +ldlayer 0, layer_3D00 +vibfreq 100 +vibdepth 100 +end + +.layer layer_3D00 +portamento 0x81, 15, 200 +notedv PITCH_E4, 0x96, 100 +end + +.channel enemy_poe_hurt +instr FONT01_INSTR_POE_DISAPPEAR +ldlayer 0, layer_3D14 +ldlayer 1, layer_4829 +gain 24 +end + +.layer layer_3D14 +portamento 0x81, 49, 200 +notedv PITCH_A5, 0xA, 100 +portamento 0x81, 60, 155 +notedv PITCH_E5, 0x1E, 100 +end + +.channel enemy_poe_die +ldlayer 0, layer_3D2C +ldlayer 1, layer_4829 +gain 24 +end + +.layer layer_3D2C +instr FONT01_INSTR_POE_DISAPPEAR +portamento 0x81, 49, 200 +notedv PITCH_A5, 0xA, 100 +portamento 0x81, 60, 155 +notedv PITCH_E5, 0x3C, 100 +end + +.channel enemy_boss_dodongo_roar +ldlayer 0, layer_3D47 +ldlayer 1, layer_3D52 +ldlayer 2, layer_3D5D +end + +.layer layer_3D47 +instr FONT01_INSTR_MONSTER_ROAR +portamento 0x85, 11, 50 +notedv PITCH_C3, 0x12C, 100 +end + +.layer layer_3D52 +instr FONT01_INSTR_MONSTER_ROAR +portamento 0x85, 13, 50 +notedv PITCH_D3, 0x122, 100 +end + +.layer layer_3D5D +instr FONT01_INSTR_DODONGO_ROAR +portamento 0x81, 12, 255 +notedv PITCH_DF2, 0xC8, 100 +end + +.channel enemy_boss_gohma_eyeroll +instr FONT01_INSTR_EGG_CRACK +ldlayer 0, layer_3D75 +ldlayer 1, layer_3D73 +gain 18 +end + +.layer layer_3D73 +transpose 4 + +.layer layer_3D75 +portamento 0x81, 3, 200 +notedv PITCH_E1, 0x8C, 100 +end + +.channel enemy_boss_dodongo_die +ldlayer 0, layer_3DB4 +ldlayer 1, layer_3D8F +ldlayer 2, layer_3D91 +ldlayer 3, layer_4829 +vibfreq 20 +vibdepth 50 +end + +.layer layer_3D8F +transpose -6 + +.layer layer_3D91 +instr FONT01_INSTR_DODONGO_ROAR +portamento 0x85, 38, 255 +notedv PITCH_E4, 0x1E, 100 +notedv PITCH_B2, 0x96, 100 +transpose -5 +env envelope_69DC, 127 +portamento 0x85, 31, 255 +notedv PITCH_A3, 0x3C, 80 +env envelope_6A3C, 127 +notedv PITCH_D2, 0xE6, 80 +end + +.layer layer_3DB4 +instr FONT01_INSTR_MONSTER_ROAR +env envelope_69CC, 230 +portamento 0x81, 15, 20 +notedv PITCH_E3, 0x96, 100 +env envelope_6A2C, 240 +portamento 0x81, 31, 100 +notedv PITCH_C2, 0x10E, 100 +end + +.channel enemy_boss_dodongo_dying_groan +ldlayer 0, layer_3DDF +ldlayer 1, layer_3DEA +ldlayer 2, layer_3DF5 +gain 20 +vibfreq 70 +vibdepth 50 +end + +.layer layer_3DDF +instr FONT01_INSTR_MONSTER_ROAR +portamento 0x81, 13, 50 +notedv PITCH_D3, 0x118, 100 +end + +.layer layer_3DEA +instr FONT01_INSTR_MONSTER_ROAR +portamento 0x81, 11, 50 +notedv PITCH_C3, 0x122, 100 +end + +.layer layer_3DF5 +instr FONT01_INSTR_DODONGO_ROAR +portamento 0x81, 12, 255 +notedv PITCH_DF2, 0xC8, 100 +end + +.channel enemy_boss_dodongo_fossilize +instr 2 +ldlayer 0, layer_3E0F +ldlayer 1, layer_3E11 +gain 16 +vibfreq 10 +vibdepth 20 +end + +.layer layer_3E0F +transpose -8 + +.layer layer_3E11 +notedv PITCH_E2, 30000, 100 +rjump layer_3E11 + +.channel enemy_boss_dodongo_lava +instr FONT01_INSTR_EXPLOSION_LAVA +env envelope_682C +gain 20 +ldlayer 0, layer_3E25 +ldlayer 1, layer_3E29 +end + +.layer layer_3E25 +transpose 42 +rjump layer_3E2B + +.layer layer_3E29 +transpose 48 +.layer layer_3E2B +notedv PITCH_C5, 0x46, 100 +notedv PITCH_F4, 0x46, 100 +notedv PITCH_C4, 0x46, 100 +notedv PITCH_BF3, 0x32, 100 +notedv PITCH_G3, 0x28, 100 +notedv PITCH_EF3, 0x28, 100 +notedv PITCH_D3, 0x1E, 100 +notedv PITCH_BF2, 0x1E, 100 +end + +.channel enemy_boss_dodongo_hurt +instr FONT01_INSTR_DODONGO_ROAR +env envelope_683C +ldlayer 0, layer_3E60 +ldlayer 1, layer_3E56 +ldlayer 2, layer_3E58 +ldlayer 3, layer_4829 +end + +.layer layer_3E56 +transpose -8 + +.layer layer_3E58 +portamento 1, 38, 20 +notedv PITCH_EF4, 0x50, 100 +end + +.layer layer_3E60 +portamento 0x85, 31, 150 +notedv PITCH_C4, 0x14, 100 +notedv PITCH_B3, 0x46, 100 +end + +.channel enemy_stalfos_jump +ldlayer 0, layer_3E6F +end + +.layer layer_3E6F +instr FONT01_INSTR_GUNSHOT +env envelope_686C, 255 +transpose 4 +portamento 0x81, 26, 50 +notedv PITCH_B5, 0x50, 100 +end + +.channel enemy_boss_gohma_die +env envelope_687C +ldlayer 0, layer_3E93 +ldlayer 1, layer_3E95 +ldlayer 2, layer_3EB4 +ldlayer 3, layer_4829 +vibfreq 20 +vibdepth 50 +end + +.layer layer_3E93 +transpose -6 + +.layer layer_3E95 +instr FONT01_INSTR_DINO_ROAR +portamento 0x85, 38, 255 +notedv PITCH_E4, 0x1E, 100 +notedv PITCH_B2, 0x96, 100 +transpose -5 +portamento 0x85, 32, 255 +notedv PITCH_C4, 0x3C, 80 +env envelope_6A3C, 200 +notedv PITCH_B2, 0xC8, 80 +end + +.layer layer_3EB4 +instr FONT01_INSTR_MONSTER_ROAR +env envelope_69CC, 200 +portamento 0x81, 15, 20 +notedv PITCH_E3, 0x96, 100 +env envelope_6A2C, 200 +portamento 0x81, 31, 100 +notedv PITCH_C2, 0x12C, 100 +end + +.channel enemy_scrub_emerge +instr FONT01_INSTR_GRASS_RUSTLE +ldlayer 0, layer_3ED8 +ldlayer 1, layer_3EDA +end + +.layer layer_3ED8 +transpose -2 + +.layer layer_3EDA +portamento 0x81, 31, 64 +notedv PITCH_C4, 0x32, 100 +end + +.channel enemy_scrub_burrow +instr FONT01_INSTR_GRASS_RUSTLE +ldlayer 0, layer_3EEB +ldlayer 1, layer_3EED +end + +.layer layer_3EEB +transpose -2 + +.layer layer_3EED +portamento 0x81, 39, 64 +notedv PITCH_E3, 0x32, 100 +end + +.channel enemy_scrub_spit +instr 2 +ldlayer 0, layer_3EFD +gain 32 +end + +.layer layer_3EFD +portamento 0x81, 31, 64 +notedv PITCH_C4, 0xC, 100 +end + +.channel enemy_scrub_walk +ldlayer 0, layer_3F0C +ldlayer 1, layer_5320 +end + +.layer layer_3F0C +instr FONT01_INSTR_GRASS_RUSTLE +notedv PITCH_DF4, 0x20, 70 +end + +.channel enemy_scrub_hurt +ldlayer 0, layer_3F16 +end + +.layer layer_3F16 +instr FONT01_INSTR_SCRUB_DEATH +transpose 4 +portamento 0x81, 51, 255 +notedv PITCH_B5, 0xA, 100 +portamento 0x81, 60, 255 +notedv PITCH_E5, 0x19, 100 +end + +.channel enemy_scrub_die +ldlayer 0, layer_3F2D +end + +.layer layer_3F2D +instr FONT01_INSTR_SCRUB_DEATH +portamento 0x81, 59, 255 +notedv PITCH_E5, 0xA, 100 +portamento 0x81, 51, 255 +notedv PITCH_F4, 0x1E, 100 +end + +.channel enemy_boss_gohma_dissolve +ldlayer 0, layer_3F49 +ldlayer 1, layer_3F4B +vibfreq 10 +vibdepth 20 +end + +.layer layer_3F49 +transpose -1 + +.layer layer_3F4B +instr 2 +.layer layer_3F4D +notedv PITCH_EF1, 30000, 100 +rjump layer_3F4D + +.channel enemy_tektite_hurt +instr FONT01_INSTR_GUAY_HURT +env envelope_65D8 +ldlayer 0, layer_3F5F +ldlayer 1, layer_4829 +end + +.layer layer_3F5F +portamento 0x81, 36, 255 +notedv PITCH_E4, 0xA, 100 +portamento 0x81, 44, 255 +notedv PITCH_B3, 0x1E, 100 +end + +.channel enemy_tektite_die +ldlayer 0, layer_3F78 +ldlayer 1, layer_3F89 +ldlayer 2, layer_4829 +end + +.layer layer_3F78 +instr FONT01_INSTR_DODONGO_ROAR +portamento 0x81, 32, 255 +notedv PITCH_C4, 0xA, 100 +portamento 0x81, 40, 255 +notedv PITCH_G3, 0x5C, 100 +end + +.layer layer_3F89 +instr FONT01_INSTR_GUAY_HURT +portamento 0x81, 43, 255 +notedv PITCH_B4, 0xF, 80 +portamento 0x81, 48, 255 +notedv PITCH_EF4, 0x24, 80 +end + +.channel enemy_stinger_hurt +instr FONT01_INSTR_GUAY_HURT +ldlayer 0, layer_3FA7 +ldlayer 1, layer_4829 +vibfreq 48 +vibdepth 48 +end + +.layer layer_3FA7 +transpose -10 +rjump layer_3F5F +end + +.channel enemy_stinger_die +ldlayer 0, layer_3FBA +ldlayer 1, layer_3FCB +ldlayer 2, layer_4829 +vibfreq 48 +vibdepth 48 +end + +.layer layer_3FBA +instr FONT01_INSTR_DODONGO_ROAR +portamento 0x81, 22, 127 +notedv PITCH_DF4, 0x28, 100 +portamento 0x81, 38, 255 +notedv PITCH_A2, 0x7F, 100 +end + +.layer layer_3FCB +transpose -12 +rjump layer_3F89 +end + +.channel enemy_skulltula_hurt +ldlayer 0, layer_4829 +ldlayer 1, layer_3FD7 +end + +.layer layer_3FD7 +instr FONT01_INSTR_DINO_INHALE +portamento 0x81, 51, 255 +notedv PITCH_B5, 0xA, 100 +portamento 0x81, 60, 255 +notedv PITCH_E5, 0x14, 100 +end + +.channel enemy_gold_skull_cry +ldlayer 0, layer_3FD7 +end + +.channel enemy_skulltula_pivot +instr FONT01_INSTR_OWL_FLAP +ldlayer 0, layer_3FF2 +end + +.layer layer_3FF2 +portamento 0x81, 51, 255 +notedv PITCH_B5, 0x14, 100 +portamento 0x81, 60, 255 +notedv PITCH_E5, 0x14, 100 +end + +.channel enemy_skullwall_die +ldlayer 0, layer_400C +ldlayer 1, layer_4829 +vibfreq 100 +vibdepth 127 +end + +.layer layer_400C +instr FONT01_INSTR_DINO_ROAR +legato +portamento 0x85, 29, 255 +notedv PITCH_BF3, 0x14, 100 +notedv PITCH_BF2, 0x3C, 100 +end + +.channel enemy_dissolve +instr 2 +env envelope_68DC +ldlayer 0, layer_4023 +end + +.layer layer_4023 +portamento 0x81, 7, 100 +notedv PITCH_A1, 0x19, 100 +end + +.channel enemy_boss_gohma_thrust +instr FONT01_INSTR_MONSTER_ROAR +env envelope_68EC +ldlayer 0, layer_4038 +vibfreq 100 +vibdepth 50 +end + +.layer layer_4038 +portamento 0x81, 45, 250 +notedv PITCH_GF3, 0x28, 100 +end + +.channel enemy_lizalfos_cry +ldlayer 0, layer_404B +ldlayer 1, layer_4057 +vibfreq 50 +vibdepth 60 +end + +.layer layer_404B +instr FONT01_INSTR_BABA_LUNGE +transpose 48 +portamento 0x81, 32, 100 +notedv PITCH_D3, 0x23, 80 +end + +.layer layer_4057 +instr FONT01_INSTR_LIZALFOS +portamento 0x81, 39, 100 +notedv PITCH_A3, 0x28, 100 +end + +.channel enemy_lizalfos_attack_shout +ldlayer 1, layer_406B +ldlayer 0, layer_4077 +ldlayer 2, layer_4081 +end + +.layer layer_406B +instr FONT01_INSTR_BABA_LUNGE +transpose 48 +portamento 0x81, 34, 200 +notedv PITCH_B3, 0x23, 80 +end + +.layer layer_4077 +instr FONT01_INSTR_LIZALFOS +portamento 0x81, 39, 255 +notedv PITCH_F4, 0x32, 100 +end + +.layer layer_4081 +instr FONT01_INSTR_GERUDO_ATTACK +env envelope_682C, 240 +ldelay 0xA +notedv PITCH_D4, 0x1E, 100 +end + +.channel enemy_dodongo_swipe +instr FONT01_INSTR_GUNSHOT +env envelope_686C +ldlayer 0, layer_4098 +gain 20 +end + +.layer layer_4098 +transpose 5 +portamento 0x81, 26, 200 +notedv PITCH_B5, 0xC8, 100 +end + +.channel enemy_poe_transform +instr FONT01_INSTR_POE_DISAPPEAR +env envelope_69BC +ldlayer 0, layer_40B0 +vibfreq 100 +vibdepth 100 +end + +.layer layer_40B0 +portamento 0x81, 55, 255 +notedv PITCH_C3, 0x50, 100 +end + +.channel enemy_wallmaster_fall +instr FONT01_INSTR_POE_DISAPPEAR +ldlayer 0, layer_40C1 +ldlayer 1, layer_40C3 +end + +.layer layer_40C1 +transpose -6 + +.layer layer_40C3 +notedv PITCH_C3, 0x1A0, 100 +end + +.channel enemy_wallmaster_retreat +instr FONT01_INSTR_POE_DISAPPEAR +env envelope_69FC +ldlayer 0, layer_40D3 +gain 16 +end + +.layer layer_40D3 +portamento 0x81, 36, 100 +notedv PITCH_C4, 0x78, 100 +end + +.channel enemy_floormaster_walk +instr FONT01_INSTR_EGG_CRACK +ldlayer 0, layer_40E3 +gain 20 +end + +.layer layer_40E3 +portamento 0x81, 9, 128 +notedv PITCH_A1, 0xF, 100 +end + +.channel enemy_floormaster_hurt +instr FONT01_INSTR_DINO_ROAR +ldlayer 0, layer_40F8 +ldlayer 1, layer_4829 +vibfreq 100 +vibdepth 70 +end + +.layer layer_40F8 +legato +portamento 0x85, 42, 128 +notedv PITCH_AF4, 0x1E, 100 +notedv PITCH_C4, 0x28, 100 +end + +.channel enemy_floormaster_die +ldlayer 0, layer_410F +ldlayer 1, layer_4829 +vibfreq 132 +vibdepth 70 +end + +.layer layer_410F +instr FONT01_INSTR_DINO_ROAR +legato +portamento 0x85, 46, 128 +notedv PITCH_C5, 0x28, 100 +notedv PITCH_E4, 0x30, 100 +end + +.channel enemy_biri_float +instr FONT01_INSTR_STALFOS_ATTACK +env envelope_6A0C +ldlayer 0, layer_4126 +end + +.layer layer_4126 +legato +portamento 0x85, 31, 255 +notedv PITCH_A3, 0x32, 100 +notedv PITCH_AF2, 0x46, 100 +end + +.channel enemy_biri_fly +ldlayer 0, layer_414B +ldlayer 1, layer_4139 +end + +.layer layer_4139 +instr 2 +env envelope_6A0C, 220 +legato +portamento 0x85, 27, 200 +notedv PITCH_F3, 0x14, 60 +notedv PITCH_E2, 0x32, 60 +end + +.layer layer_414B +instr FONT01_INSTR_STALFOS_ATTACK +env envelope_6A0C, 128 +legato +portamento 0x85, 31, 200 +notedv PITCH_A3, 0x32, 100 +notedv PITCH_AF2, 0x46, 100 +end + +.channel enemy_biri_shock +instr FONT01_INSTR_GANONDORF_ATTACK_0 +.channel chan_415F +ldlayer 0, layer_4179 +.channel chan_4162 +rand 6 +stseq 3, layer_4179+1 +stseq 3, chan_4172+1 +rand 8 +stseq 91, layer_4179 +.channel chan_4172 +ldi 1 +call delay_varyingvol +rjump chan_4162 + +.layer layer_4179 +notedv PITCH_C3, 0x50, 80 +rjump layer_4179 + +.channel enemy_boss_ganon_transform +instr FONT01_INSTR_GANONDORF_ATTACK_0 +releaserate 208 +rjump chan_415F + +.channel enemy_biri_die +ldlayer 0, layer_4829 +ldlayer 1, layer_418B +end + +.layer layer_418B +instr FONT01_INSTR_GUAY_HURT +portamento 0x81, 32, 255 +notedv PITCH_C4, 0xA, 100 +portamento 0x81, 41, 255 +notedv PITCH_F3, 0xE, 100 +end + +.channel enemy_torch_slug_hurt +ldlayer 0, layer_41A6 +ldlayer 1, layer_41B8 +ldlayer 2, layer_4829 +end + +.layer layer_41A6 +instr FONT01_INSTR_DINO_ROAR +legato +portamento 0x81, 32, 64 +notedv PITCH_C4, 0x14, 80 +portamento 0x81, 37, 255 +notedv PITCH_BF2, 0x24, 80 +end + +.layer layer_41B8 +transpose -8 +rjump layer_418B + +.channel enemy_biri_die_bubbles +ldlayer 0, layer_41C0 +end + +.layer layer_41C0 +instr FONT01_INSTR_WATER_BUBBLES +env envelope_6A1C, 249 +portamento 0x81, 25, 255 +notedv PITCH_G3, 0x90, 100 +end + +.channel enemy_phantom_reveal +instr FONT01_INSTR_DINO_ROAR +env envelope_69CC +ldlayer 0, layer_41E0 +vibfreqgrad 70, 110, 18 +vibdepthgrad 20, 80, 10 +end + +.layer layer_41E0 +portamento 0x81, 21, 255 +notedv PITCH_BF2, 0xE6, 100 +end + +.channel enemy_phantom_lightning +ldlayer 0, layer_41EF +gain 22 +end + +.layer layer_41EF +instr FONT01_INSTR_ELECTRIC_ATTACK +notedv PITCH_C4, 0x118, 100 +end + +.channel enemy_ganondorf_charge +instr FONT01_INSTR_GANONDORF_ATTACK_0 +ldlayer 0, layer_41FE +gain 20 +end + +.layer layer_41FE +notedv PITCH_A3, 0x50, 100 +end + +.channel enemy_ganondorf_fly +instr FONT01_INSTR_GANONDORF_FLY +ldlayer 0, layer_4208 +end + +.layer layer_4208 +notedv PITCH_D4, 30000, 100 +rjump layer_4208 + +.channel enemy_witch_charge +ldlayer 0, layer_4214 +gain 24 +end + +.layer layer_4214 +instr FONT01_INSTR_GANONDORF_CHARGE +notedv PITCH_F4, 0x5A, 100 +end + +.channel enemy_phantom_painting_enter +ldlayer 0, layer_4220 +gain 24 +end + +.layer layer_4220 +instr FONT01_INSTR_SWOOSH +notedv PITCH_D4, 0x5A, 100 +end + +.channel enemy_phantom_shout +instr FONT01_INSTR_PHANTOM_ATTACK +ldlayer 0, layer_422E +gain 24 +end + +.layer layer_422E +portamento 0x81, 39, 50 +notedv PITCH_F4, 0x30, 100 +end + +.channel enemy_ganondorf_orb_trail +ldlayer 0, layer_423E +vibfreq 128 +vibdepth 128 +end + +.layer layer_423E +instr 2 +legato +portamento 0x81, 37, 255 +.layer layer_4245 +notedv PITCH_GF3, 0xC8, 100 +rjump layer_4245 + +.channel enemy_boss_twinrova_ice_reflected +ldlayer 0, layer_4256 +ldlayer 1, layer_4B32 +vibfreq 128 +vibdepth 96 +end + +.layer layer_4256 +instr 2 +transpose 12 +legato +rjump layer_4245 + +.channel enemy_ganondorf_lightning_hit +ldlayer 0, layer_4261 +end + +.layer layer_4261 +instr FONT01_INSTR_ELECTRIC_ATTACK +notedv PITCH_C5, 0x8C, 100 +end + +.channel enemy_phantom_attack_unused +instr FONT01_INSTR_THUNDERBURST +env envelope_6A5C +ldlayer 0, layer_4273 +gain 16 +end + +.layer layer_4273 +notedv PITCH_E3, 0x1C2, 100 +end + +.channel enemy_phantom_staff +instr FONT01_INSTR_SWOOSH +ldlayer 0, layer_4280 +gain 20 +end + +.layer layer_4280 +ldelay 0xF +notedv PITCH_C4, 0x7, 100 +notedv PITCH_G4, 0x7, 100 +notedv PITCH_C5, 0x7, 100 +notedv PITCH_G5, 0x7, 100 +notedv PITCH_E4, 0x7, 100 +notedv PITCH_B4, 0x7, 100 +notedv PITCH_E5, 0x7, 100 +notedv PITCH_B5, 0x7, 100 +end + +.channel enemy_phantom_eyes +instr FONT01_INSTR_GANONDORF_CHARGE +env envelope_699C +ldlayer 0, layer_42AA +gain 20 +vibfreq 128 +vibdepth 20 +end + +.layer layer_42AA +portamento 0x81, 33, 255 +notedv PITCH_DF3, 0x6E, 100 +end + +.channel enemy_phantom_orb_dissipate +instr FONT01_INSTR_THUNDERBURST +ldlayer 0, layer_42B8 +end + +.layer layer_42B8 +portamento 0x81, 60, 200 +notedv PITCH_C3, 0x1E, 100 +end + +.channel enemy_phantom_die_roar +instr FONT01_INSTR_PHANTOM_WAIL +ldlayer 0, layer_42E9 +ldlayer 1, layer_42DD +ldlayer 2, layer_42D4 +gain 20 +releaserate 244 +vibfreq 50 +vibdepth 30 +end + +.layer layer_42D4 +portamento 0x81, 46, 100 +notedv PITCH_D4, 0xB4, 100 +end + +.layer layer_42DD +ldelay 0x96 +portamento 0x81, 36, 220 +notedv PITCH_E3, 0xD2, 100 +end + +.layer layer_42E9 +ldelay 0x14A +portamento 0x81, 31, 200 +notedv PITCH_A2, 0x14A, 100 +end + +.channel enemy_phantom_hurt +ldlayer 0, layer_4301 +ldlayer 1, layer_430F +ldlayer 2, layer_4829 +gain 20 +end + +.layer layer_4301 +instr FONT01_INSTR_PHANTOM_WAIL +legato +portamento 0x85, 39, 100 +notedv PITCH_A4, 0x1E, 100 +notedv PITCH_C4, 0x3C, 100 +end + +.layer layer_430F +instr FONT01_INSTR_GANONDORF_ATTACK_0 +legato +portamento 0x81, 29, 100 +notedv PITCH_E4, 0x14, 68 +portamento 0x81, 34, 255 +notedv PITCH_G2, 0x24, 68 +end + +.channel enemy_deadhand_hurt +ldlayer 0, layer_4328 +ldlayer 1, layer_4829 +end + +.layer layer_4328 +transpose -7 +rjump layer_4301 + +.channel enemy_phantom_die +ldlayer 0, layer_433B +ldlayer 1, layer_434A +ldlayer 2, layer_434C +ldlayer 3, layer_4829 +gain 20 +end + +.layer layer_433B +instr FONT01_INSTR_PHANTOM_WAIL +legato +portamento 0x85, 36, 255 +notedv PITCH_GF4, 0x50, 100 +notedv PITCH_AF2, 500, 100 +end + +.layer layer_434A +transpose -16 + +.layer layer_434C +instr FONT01_INSTR_THUNDERBURST +notedv PITCH_AF4, 0x1C2, 100 +end + +.channel enemy_deadhand_die +ldlayer 0, layer_435A +ldlayer 1, layer_4829 +end + +.layer layer_435A +transpose -8 +rjump layer_433B + +.channel enemy_phantom_hurt_orb +instr FONT01_INSTR_PHANTOM_WAIL +ldlayer 0, layer_436C +gain 20 +releaserate 249 +vibfreq 127 +vibdepth 70 +end + +.layer layer_436C +legato +portamento 0x85, 30, 100 +notedv PITCH_G3, 0x1E, 100 +notedv PITCH_C3, 0x14, 100 +end + +.channel enemy_phantom_laugh +instr FONT01_INSTR_PHANTOM_LAUGH_1 +ldlayer 0, layer_4380 +gain 16 +end + +.layer layer_4380 +notedv PITCH_BF3, 0x160, 100 +end + +.channel enemy_moblin_walk +instr FONT01_INSTR_SMASH +env envelope_68EC +ldlayer 0, layer_438E +end + +.layer layer_438E +portamento 0x81, 28, 64 +notedv PITCH_GF2, 0xD, 76 +end + +.channel enemy_moblin_dash +instr FONT01_INSTR_SMASH +env envelope_68EC +ldlayer 0, layer_439F +end + +.layer layer_439F +portamento 0x81, 32, 64 +notedv PITCH_BF2, 0x1D, 100 +end + +.channel enemy_moblin_slide +ldlayer 0, layer_43AE +ldlayer 1, layer_43B0 +end + +.layer layer_43AE +transpose -5 + +.layer layer_43B0 +instr FONT01_INSTR_TEKTITE_ROTATE +notedv PITCH_C2, 0x78, 100 +end + +.channel enemy_octorok_jump +instr FONT01_INSTR_WATER_SPLASH_L +ldlayer 0, layer_43BC +end + +.layer layer_43BC +portamento 0x81, 40, 100 +notedv PITCH_AF4, 0x64, 80 +end + +.channel enemy_octorok_dive +instr FONT01_INSTR_WATER_SPLASH_L +ldlayer 0, layer_43CA +end + +.layer layer_43CA +portamento 0x81, 38, 100 +notedv PITCH_E3, 0x30, 100 +end + +.channel enemy_octorok_bubble +ldlayer 0, layer_43D6 +end + +.layer layer_43D6 +instr FONT01_INSTR_STEP_WATER +notedv PITCH_B1, 0x66, 100 +end + +.channel enemy_octorok_float +instr FONT01_INSTR_STEP_WATER +ldlayer 0, layer_43E2 +end + +.layer layer_43E2 +portamento 0x81, 23, 100 +notedv PITCH_BF2, 0x30, 68 +end + +.channel enemy_tektite_land_water1 +instr FONT01_INSTR_WATER_SPLASH_L +ldlayer 0, layer_43F0 +end + +.layer layer_43F0 +portamento 0x81, 47, 100 +notedv PITCH_DF4, 0x50, 80 +end + +.channel enemy_octorok_rock_break +ldlayer 0, layer_43FC +end + +.layer layer_43FC +instr FONT01_INSTR_EXPLOSION_LAVA +env envelope_68EC, 251 +notedv PITCH_A2, 0x2C, 100 +end + +.channel enemy_bubble_dash +instr FONT01_INSTR_POT_BREAK +ldlayer 0, layer_440C +end + +.layer layer_440C +portamento 0x81, 8, 255 +notedv PITCH_C2, 0x6, 70 +portamento 0x81, 14, 255 +notedv PITCH_A1, 0x8, 70 +end + +.channel enemy_bubble_cry +ldlayer 0, layer_4423 +vibfreq 96 +vibdepth 128 +end + +.layer layer_4423 +instr FONT01_INSTR_PHANTOM_LAUGH_0 +notedv PITCH_E4, 0x54, 100 +end + +.channel enemy_bubble_flame_appear +instr FONT01_INSTR_DODONGO_ROAR +env envelope_6A0C +ldlayer 0, layer_443A +vibfreqgrad 70, 110, 18 +vibdepthgrad 20, 80, 10 +end + +.layer layer_443A +portamento 0x81, 19, 255 +notedv PITCH_AF2, 0x46, 100 +end + +.channel enemy_bubble_flame_vanish +instr FONT01_INSTR_DODONGO_ROAR +env envelope_6A0C +ldlayer 0, layer_4453 +vibfreqgrad 70, 110, 18 +vibdepthgrad 20, 80, 10 +end + +.layer layer_4453 +portamento 0x81, 23, 255 +notedv PITCH_E2, 0x46, 100 +end + +.channel enemy_moblin_attack_shout +instr FONT01_INSTR_LIZALFOS +ldlayer 0, layer_4463 +gain 16 +end + +.layer layer_4463 +portamento 0x81, 17, 255 +notedv PITCH_A2, 0x96, 100 +end + +.channel enemy_moblin_grunt +instr FONT01_INSTR_MOBLIN_GROWL +ldlayer 0, layer_4474 +gain 16 +end + +.layer layer_4474 +portamento 0x81, 21, 255 +notedv PITCH_DF2, 0x44, 100 +end + +.channel enemy_moblin_spear_relax +instr FONT01_INSTR_GULP_SPEAR +ldlayer 0, layer_4482 +end + +.layer layer_4482 +transpose 42 +notedv PITCH_F4, 0xA, 100 +end + +.channel enemy_moblin_spear_point +instr FONT01_INSTR_GULP_SPEAR +ldlayer 0, layer_4490 +gain 20 +end + +.layer layer_4490 +transpose 44 +notedv PITCH_B3, 0x1D, 100 +end + +.channel enemy_moblin_club_strike +instr FONT01_INSTR_GERUDO_ATTACK +ldlayer 0, layer_449C +end + +.layer layer_449C +portamento 0x81, 25, 255 +notedv PITCH_F2, 0x78, 100 +end + +.channel enemy_moblin_club_lift +instr FONT01_INSTR_GERUDO_ATTACK +ldlayer 0, layer_44AA +end + +.layer layer_44AA +portamento 0x81, 16, 255 +notedv PITCH_B2, 0x78, 100 +end + +.channel enemy_moblin_die +ldlayer 0, layer_44B9 +ldlayer 1, layer_4829 +end + +.layer layer_44B9 +instr FONT01_INSTR_LIZALFOS +legato +portamento 0x85, 23, 200 +notedv PITCH_C3, 0x1E, 100 +notedv PITCH_DF2, 0x3C, 100 +end + +.channel enemy_boss_volvagia_rock +instr FONT01_INSTR_EXPLOSION_LAVA +ldlayer 0, layer_44D7 +gain 20 +rand 4 +stseq 107, layer_44D7 +releaserate 232 +end + +.layer layer_44D7 +notedv PITCH_F4, 0x32, 100 +end + +.channel enemy_boss_volvagia_roar +ldlayer 0, layer_44EB +ldlayer 1, layer_44E4 +gain 20 +end + +.layer layer_44E4 +instr FONT01_INSTR_THUNDER_HURT +notedv PITCH_D4, 0xA8, 100 +end + +.layer layer_44EB +instr FONT01_INSTR_DINO_ROAR +legato +portamento 0x81, 43, 255 +notedv PITCH_GF4, 0xA, 100 +portamento 0x81, 45, 255 +notedv PITCH_A4, 0xA8, 100 +end + +.channel enemy_boss_ganon_roar +ldlayer 0, layer_4508 +ldlayer 1, layer_450F +ldlayer 2, layer_4513 +end + +.layer layer_4508 +instr FONT01_INSTR_MONSTER_ROAR +notedv PITCH_E4, 0xB4, 100 +end + +.layer layer_450F +transpose -2 +rjump layer_44EB + +.layer layer_4513 +transpose 6 +rjump layer_44E4 + +.channel enemy_volvagia_fall +ldlayer 0, layer_4532 +ldlayer 1, layer_4524 +gain 20 +vibfreq 120 +vibdepth 64 +end + +.layer layer_4524 +instr FONT01_INSTR_DINO_ROAR +legato +portamento 0x85, 39, 255 +notedv PITCH_F4, 0x14, 80 +notedv PITCH_C3, 0x6E, 80 +end + +.layer layer_4532 +instr FONT01_INSTR_THUNDER_HURT +legato +portamento 0x85, 39, 255 +notedv PITCH_A4, 0x14, 100 +notedv PITCH_C2, 0xC8, 100 +end + +.channel enemy_volvagia_paralyzed +instr FONT01_INSTR_DINO_ROAR +gain 20 +ldlayer 0, layer_4549 +end + +.layer layer_4549 +legato +portamento 0x85, 19, 255 +notedv PITCH_GF2, 0x1E, 100 +notedv PITCH_B1, 0x1E, 100 +end + +.channel enemy_boss_volvagia_cry +ldlayer 0, layer_4564 +ldlayer 1, layer_455E +gain 20 +end + +.layer layer_455E +instr FONT01_INSTR_THUNDER_HURT +notedv PITCH_AF4, 0x78, 100 +end + +.layer layer_4564 +instr FONT01_INSTR_DINO_ROAR +legato +portamento 0x81, 49, 255 +notedv PITCH_C5, 0xA, 100 +portamento 0x81, 51, 255 +notedv PITCH_EF5, 0x78, 100 +end + +.channel enemy_boss_ganon_hurt +ldlayer 0, layer_4580 +ldlayer 1, layer_4564 +ldlayer 2, layer_4584 +end + +.layer layer_4580 +transpose -6 +rjump layer_4564 + +.layer layer_4584 +instr FONT01_INSTR_MONSTER_ROAR +legato +portamento 0x85, 40, 200 +notedv PITCH_AF4, 0x10, 100 +notedv PITCH_D3, 0xB4, 100 +end + +.channel enemy_boss_volvagia_hole +ldlayer 0, layer_45A0 +ldlayer 1, layer_45AC +gain 20 +vibfreq 10 +vibdepth 20 +end + +.layer layer_45A0 +instr FONT01_INSTR_EXPLOSION_LAVA +env envelope_68B4, 220 +.layer layer_45A6 +notedv PITCH_GF2, 0x118, 100 +rjump layer_45A6 + +.layer layer_45AC +instr 2 +.layer layer_45AE +notedv PITCH_B0, 30000, 100 +rjump layer_45AE + +.channel enemy_boss_volvagia_swipe +instr FONT01_INSTR_GERUDO_ATTACK +ldlayer 0, layer_45BA +end + +.layer layer_45BA +portamento 0x81, 28, 255 +notedv PITCH_C4, 0x40, 100 +end + +.channel enemy_redead_moan +instr FONT01_INSTR_GORON_YAWN +ldlayer 0, layer_45CB +ldlayer 1, layer_45CD +end + +.layer layer_45CB +ldelay 0x18 + +.layer layer_45CD +notedv PITCH_E3, 0x170, 80 +end + +.channel enemy_redead_scream +ldlayer 0, layer_45D9 +ldlayer 1, layer_45DF +end + +.layer layer_45D9 +instr FONTANY_INSTR_SFX +notedv FONT01_EFFECT_REDEAD_SCREAM, 0x0, 100 +end + +.layer layer_45DF +instr FONT01_INSTR_DINO_ROAR +portamento 0x81, 30, 255 +notedv PITCH_BF3, 0x2E, 100 +end + +.channel enemy_redead_hurt +instr FONT01_INSTR_GORON_YAWN +ldlayer 0, layer_45F5 +ldlayer 1, layer_45F7 +ldlayer 2, layer_4829 +end + +.layer layer_45F5 +ldelay 0x18 + +.layer layer_45F7 +portamento 0x81, 34, 255 +notedv PITCH_E2, 0x44, 100 +end + +.channel enemy_redead_die +instr FONT01_INSTR_GORON_YAWN +ldlayer 0, layer_460B +ldlayer 1, layer_460D +ldlayer 2, layer_4829 +end + +.layer layer_460B +ldelay 0x18 + +.layer layer_460D +legato +portamento 0x85, 30, 255 +notedv PITCH_F3, 0x1E, 100 +notedv PITCH_EF2, 0x84, 100 +end + +.channel enemy_poe_laugh +instr FONT01_INSTR_PHANTOM_LAUGH_1 +gain 20 +ldlayer 0, layer_4625 +ldlayer 1, layer_4627 +end + +.layer layer_4625 +ldelay 0x16 + +.layer layer_4627 +notedv PITCH_BF5, 0x62, 100 +end + +.channel enemy_poe_sister_attack +instr FONT01_INSTR_GUNSHOT +env envelope_686C +ldlayer 0, layer_4634 +end + +.layer layer_4634 +portamento 0x81, 33, 200 +notedv PITCH_GF4, 0x22, 100 +end + +.channel enemy_redead_attack +ldlayer 0, layer_4643 +ldlayer 1, layer_4651 +end + +.layer layer_4643 +instr FONT01_INSTR_GORON_YAWN +env envelope_68EC, 250 +portamento 0x81, 30, 255 +notedv PITCH_B2, 0x30, 100 +end + +.layer layer_4651 +instr FONT01_INSTR_SMASH +env envelope_692C, 250 +portamento 0x81, 17, 50 +notedv PITCH_D1, 0x1E, 100 +end + +.channel enemy_poe_sister_laugh +instr FONT01_INSTR_PHANTOM_LAUGH_1 +ldlayer 0, layer_466B +ldlayer 1, layer_466D +ldlayer 2, layer_466F +end + +.layer layer_466B +ldelay 0x16 + +.layer layer_466D +ldelay 0x16 + +.layer layer_466F +notedv PITCH_GF5, 0x72, 100 +end + +.channel enemy_poe_sister_cry +instr FONT01_INSTR_POE_DISAPPEAR +ldlayer 0, layer_4679 +end + +.layer layer_4679 +portamento 0x81, 53, 120 +notedv PITCH_G4, 0x44, 100 +end + +.channel enemy_boss_morpha_rise +instr FONT01_INSTR_DINO_ROAR +ldlayer 0, layer_468B +vibfreq 20 +vibdepth 36 +end + +.layer layer_468B +env envelope_6A4C, 220 +.layer layer_468F +notedv PITCH_A1, 0xFA, 100 +rjump layer_468F + +.channel enemy_boss_morpha_attack +instr FONT01_INSTR_DINO_ROAR +ldlayer 0, layer_469F +vibfreq 127 +vibdepth 84 +end + +.layer layer_469F +env envelope_6A2C, 220 +portamento 0x81, 12, 120 +.layer layer_46A7 +notedv PITCH_A3, 0xD0, 100 +rjump layer_46A7 + +.channel enemy_boss_morpha_toss +instr FONT01_INSTR_DINO_ROAR +ldlayer 0, layer_46B7 +vibfreq 20 +vibdepth 36 +end + +.layer layer_46B7 +env envelope_69BC, 235 +legato +portamento 0x85, 0, 255 +notedv PITCH_A2, 0x2A, 100 +notedv PITCH_A0, 0x52, 100 +end + +.channel enemy_boss_morpha_grab +instr FONT01_INSTR_PHANTOM_MOAN +ldlayer 0, layer_46CF +gain 16 +end + +.layer layer_46CF +portamento 0x81, 30, 255 +notedv PITCH_C3, 0x72, 100 +end + +.channel enemy_octorok_death_gasp +instr FONT01_INSTR_LIZALFOS +env envelope_68FC +ldlayer 0, layer_46E0 +end + +.layer layer_46E0 +portamento 0x81, 17, 255 +notedv PITCH_BF2, 0x8, 100 +portamento 0x81, 26, 255 +notedv PITCH_EF1, 0xC, 100 +end + +.channel enemy_octorok_die +instr FONT01_INSTR_LIZALFOS +ldlayer 0, layer_46FC +ldlayer 1, layer_4829 +vibfreq 100 +vibdepth 100 +end + +.layer layer_46FC +portamento 0x81, 38, 255 +notedv PITCH_G3, 0x84, 100 +end + +.channel enemy_boss_morpha_demo_move +instr FONT01_INSTR_WATER_BUBBLES +ldlayer 0, layer_470D +panweight 0 +end + +.layer layer_470D +legato +portamento 0x85, 23, 255 +.layer layer_4712 +notedv PITCH_F2, 0x2C, 100 +notedv PITCH_AF2, 0x2C, 100 +rjump layer_4712 + +.channel enemy_boss_morpha_demo_bubble +instr FONT01_INSTR_WATER_BUBBLES +env envelope_6A1C +ldlayer 0, layer_472A +ldlayer 1, layer_472C +panweight 0 +gain 20 +end + +.layer layer_472A +ldelay 0x8 + +.layer layer_472C +portamento 0x81, 31, 255 +notedv PITCH_DF3, 0x74, 100 +end + +.channel enemy_boss_morpha_caught +ldlayer 0, layer_473B +ldlayer 1, layer_4742 +end + +.layer layer_473B +instr FONT01_INSTR_WATER_SPLASH_L +notedv PITCH_D4, 0x86, 100 +end + +.layer layer_4742 +instr FONT01_INSTR_DINO_ROAR +legato +portamento 0x81, 36, 100 +notedv PITCH_B4, 0x10, 80 +portamento 0x81, 41, 255 +notedv PITCH_D3, 0x6, 80 +end + +.channel enemy_boss_morpha_die +ldlayer 0, layer_4781 +ldlayer 1, layer_479D +vibdepth 144 +vibfreq 196 +ldi 56 +stio 6 +.channel chan_4761 +ldio 6 +stseq 0, layer_4788+1 +stseq 0, layer_478B+1 +stseq 0, layer_4794+1 +stseq 0, layer_4797+1 +sub 1 +stio 6 +sub 4 +rbeqz chan_4780 +ldi 6 +call delay_varyingvol +rjump chan_4761 +.channel chan_4780 +end + +.layer layer_4781 +instr FONT01_INSTR_DINO_ROAR +.layer layer_4783 +legato +portamento 0x85, 37, 255 +.layer layer_4788 +notedv PITCH_EF4, 0x1E, 100 +.layer layer_478B +notedv PITCH_G3, 0x1E, 100 +nolegato +legato +portamento 0x85, 34, 255 +.layer layer_4794 +notedv PITCH_BF4, 0x1E, 100 +.layer layer_4797 +notedv PITCH_BF3, 0x1E, 100 +nolegato +rjump layer_4783 + +.layer layer_479D +instr FONT01_INSTR_GORON_YAWN +portamento 0x85, 35, 255 +notedv PITCH_DF4, 0xE8, 100 +end + +.channel enemy_boss_morpha_water_spin +instr FONT01_INSTR_WATER_BUBBLES +ldlayer 0, layer_47AE +end + +.layer layer_47AE +legato +portamento 0x85, 25, 128 +.layer layer_47B3 +notedv PITCH_EF5, 0xC, 100 +notedv PITCH_BF2, 0xC, 100 +rjump layer_47B3 + +.channel enemy_boss_morpha_water_move +instr FONT01_INSTR_WATER_BUBBLES +env envelope_699C +ldlayer 0, layer_47C9 +ldlayer 1, layer_47CB +gain 20 +end + +.layer layer_47C9 +ldelay 0x8 + +.layer layer_47CB +portamento 0x81, 31, 255 +notedv PITCH_B2, 0x60, 100 +end + +.channel enemy_deadhand_bite +ldlayer 0, layer_47DC +ldlayer 1, layer_47E2 +gain 22 +end + +.layer layer_47DC +instr FONT01_INSTR_PHANTOM_GROWL +notedv PITCH_C4, 0x56, 100 +end + +.layer layer_47E2 +instr FONT01_INSTR_EGG_CRACK +portamento 0x81, 11, 200 +notedv PITCH_C2, 0x29, 100 +end + +.channel enemy_deadhand_move +ldlayer 0, layer_47F2 +gain 22 +end + +.layer layer_47F2 +instr FONT01_INSTR_EGG_CRACK +portamento 0x81, 9, 200 +notedv PITCH_BF1, 0x29, 100 +end + +.channel enemy_goron_wake +ldlayer 0, layer_4800 +end + +.layer layer_4800 +instr FONT01_INSTR_GORON +notedv PITCH_GF3, 0x20, 100 +end + +.channel enemy_goron_sit +ldlayer 0, layer_480A +end + +.layer layer_480A +instr FONT01_INSTR_GORON +transpose 48 +notedv PITCH_BF3, 0x84, 100 +end + +.channel enemy_deadhand_grabbed +gain 16 +ldlayer 0, layer_481C +ldlayer 1, layer_5095 +end + +.layer layer_481C +instr FONT01_INSTR_PHANTOM_GROWL +portamento 0x81, 35, 255 +notedv PITCH_E3, 0x30, 100 +end + +.channel enemy_boss_ganondorf_struck +ldlayer 0, layer_4829 +# @bug missing end. This bug turns out to be harmless in practice. + +.layer layer_4829 +instr FONTANY_INSTR_SFX +notedv FONT01_EFFECT_ENEMY_HURT, 0x0, 100 +end + +.channel chan_unused_482F +ldlayer 0, layer_4833 +end + +.layer layer_4833 +instr FONTANY_INSTR_SFX +notedv FONT01_EFFECT_GANONDORF_LAUGH_0, 0x0, 100 +end + +.channel enemy_big_octo_paralyzed +ldlayer 0, layer_4846 +ldlayer 1, layer_4850 +gain 16 +vibfreq 100 +vibdepth 100 +end + +.layer layer_4846 +instr FONT01_INSTR_LIZALFOS +portamento 0x81, 15, 255 +notedv PITCH_AF1, 0x54, 100 +end + +.layer layer_4850 +instr FONT01_INSTR_PHANTOM_WAIL +legato +portamento 0x85, 24, 100 +notedv PITCH_D3, 0x1E, 100 +notedv PITCH_A2, 0x2E, 100 +end + +.channel enemy_big_octo_walk +instr FONT01_INSTR_WATER_SPLASH_L +ldlayer 0, layer_4870 +.channel chan_4863 +rand 4 +stseq 96, layer_4870 +ldi 18 +call delay_varyingvol +rjump chan_4863 + +.layer layer_4870 +notedv PITCH_F3, 0x12, 100 +rjump layer_4870 + +.channel enemy_big_octo_grunt +instr FONT01_INSTR_GORON +ldlayer 0, layer_487F +gain 18 +releaserate 249 +end + +.layer layer_487F +notedv PITCH_DF3, 0x8, 100 +notedv PITCH_BF2, 0x1E, 100 +end + +.channel enemy_big_octo_hurt +ldlayer 0, layer_4896 +ldlayer 1, layer_48A4 +ldlayer 2, layer_4829 +gain 16 +vibfreq 100 +vibdepth 100 +end + +.layer layer_4896 +instr FONT01_INSTR_LIZALFOS +legato +portamento 0x85, 25, 255 +notedv PITCH_DF3, 0x18, 100 +notedv PITCH_GF1, 0x1C, 100 +end + +.layer layer_48A4 +instr FONT01_INSTR_PHANTOM_WAIL +legato +portamento 0x85, 30, 100 +notedv PITCH_AF3, 0xC, 100 +notedv PITCH_EF3, 0x12, 100 +end + +.channel enemy_big_octo_stop +instr FONT01_INSTR_WATER_SPLASH_L +ldlayer 0, layer_48B8 +end + +.layer layer_48B8 +portamento 0x81, 47, 100 +notedv PITCH_DF4, 0x12, 100 +portamento 0x81, 47, 100 +notedv PITCH_DF4, 0x12, 100 +portamento 0x81, 47, 100 +notedv PITCH_DF4, 0x12, 100 +portamento 0x81, 47, 100 +notedv PITCH_DF4, 0x50, 100 +end + +.channel enemy_big_octo_die +ldlayer 0, layer_48E5 +ldlayer 1, layer_48A4 +ldlayer 2, layer_4829 +gain 16 +vibfreq 100 +vibdepth 100 +end + +.layer layer_48E5 +instr FONT01_INSTR_LIZALFOS +portamento 0x85, 27, 255 +notedv PITCH_AF3, 0x18, 100 +notedv PITCH_AF1, 0x66, 100 +end + +.channel enemy_big_octo_die2 +ldlayer 0, layer_48FC +gain 18 +vibfreq 100 +vibdepth 100 +end + +.layer layer_48FC +instr FONT01_INSTR_PHANTOM_WAIL +portamento 0x85, 42, 100 +notedv PITCH_EF3, 0x70, 100 +end + +.channel enemy_boss_gohma_paralyzed +instr FONT01_INSTR_DINO_ROAR +ldlayer 0, layer_4913 +ldlayer 1, layer_4920 +vibfreq 84 +vibdepth 100 +end + +.layer layer_4913 +notedv PITCH_AF3, 0x110, 100 +env envelope_68AC, 240 +ldelay 0x88 +rjump layer_4913 + +.layer layer_4920 +env envelope_68AC, 240 +ldelay 0xCC +rjump layer_4913 + +.channel enemy_final_hit +instr FONT01_INSTR_ELECTRIC_ATTACK +ldlayer 0, layer_4931 +gain 20 +end + +.layer layer_4931 +transpose 6 +portamento 0x81, 48, 54 +notedv PITCH_BF5, 0x2C, 100 +end + +.channel enemy_boss_morpha_die_cry +ldlayer 0, layer_4959 +ldlayer 1, layer_4949 +ldlayer 2, layer_494B +vibfreq 20 +vibdepth 50 +end + +.layer layer_4949 +transpose 1 + +.layer layer_494B +instr FONT01_INSTR_PHANTOM_WAIL +legato +portamento 0x85, 39, 20 +notedv PITCH_E4, 0x10, 100 +notedv PITCH_B3, 0x56, 100 +end + +.layer layer_4959 +instr FONT01_INSTR_DINO_ROAR +portamento 0x85, 38, 255 +notedv PITCH_E4, 0x14, 80 +notedv PITCH_B2, 0x56, 80 +end + +.channel enemy_shop_scrub_cry +ldlayer 0, layer_496A +end + +.layer layer_496A +instr FONT01_INSTR_SCRUB_DEATH +portamento 0x81, 43, 255 +notedv PITCH_EF5, 0x8, 80 +portamento 0x81, 52, 255 +notedv PITCH_AF4, 0x8, 80 +end + +.channel enemy_skullwall_rotate +instr FONT01_INSTR_GRASS_RUSTLE +ldlayer 0, layer_4984 +ldlayer 1, layer_498C +end + +.layer layer_4984 +portamento 0x81, 31, 100 +notedv PITCH_C3, 0x32, 64 +end + +.layer layer_498C +ldelay 0x5 +portamento 0x81, 33, 100 +notedv PITCH_D3, 0x32, 64 +end + +.channel enemy_skullwall_dash +instr FONT01_INSTR_GRASS_RUSTLE +ldlayer 0, layer_499F +ldlayer 1, layer_49A7 +end + +.layer layer_499F +portamento 0x81, 27, 100 +notedv PITCH_E3, 0x32, 64 +end + +.layer layer_49A7 +ldelay 0x5 +portamento 0x81, 29, 100 +notedv PITCH_GF3, 0x32, 64 +end + +.channel enemy_boss_twinrova_appear +instr FONT01_INSTR_GANONDORF_CHARGE +env envelope_699C +ldlayer 0, layer_49C0 +gain 18 +vibfreq 128 +vibdepth 52 +end + +.layer layer_49C0 +portamento 0x81, 31, 255 +notedv PITCH_B2, 0x64, 100 +end + +.channel enemy_boss_twinrova_transform +ldlayer 0, layer_49D5 +ldlayer 1, layer_49DB +gain 20 +vibfreq 240 +vibdepth 240 +end + +.layer layer_49D5 +instr FONT01_INSTR_GUNSHOT +notedv PITCH_D3, 0x64, 100 +end + +.layer layer_49DB +instr FONT01_INSTR_DINO_INHALE +portamento 0x81, 7, 255 +notedv PITCH_BF3, 0xE6, 84 +end + +.channel enemy_boss_twinrova_fire_charge +instr FONT01_INSTR_DINO_INHALE +ldlayer 0, layer_49F0 +vibfreq 127 +vibdepth 84 +end + +.layer layer_49F0 +legato +portamento 0x85, 15, 120 +notedv PITCH_C4, 0xC8, 100 +.layer layer_49F9 +notedv PITCH_C4, 30000, 100 +rjump layer_49F9 + +.channel enemy_boss_twinrova_fire_hit +ldlayer 0, layer_4A09 +ldlayer 1, layer_4A0B +ldlayer 2, layer_4A17 +end + +.layer layer_4A09 +transpose -12 + +.layer layer_4A0B +instr 2 +env envelope_6A7C, 200 +.layer layer_4A11 +notedv PITCH_G3, 30000, 100 +rjump layer_4A11 + +.layer layer_4A17 +instr FONT01_INSTR_THUNDERBURST +env envelope_6A5C, 200 +notedv PITCH_GF2, 0x180, 100 +end + +.channel enemy_boss_twinrova_ice_beam +instr FONT01_INSTR_WIND +ldlayer 0, layer_4A28 +end + +.layer layer_4A28 +legato +portamento 0x85, 10, 102 +transpose 10 +notedv PITCH_F5, 0x28, 100 +transpose 0 +.layer layer_4A34 +notedv PITCH_F5, 0x64, 100 +rjump layer_4A34 + +.channel enemy_boss_twinrova_fire_reflected +ldlayer 0, layer_4A44 +ldlayer 1, layer_4B32 +vibfreq 128 +vibdepth 96 +end + +.layer layer_4A44 +instr FONT01_INSTR_WIND +transpose 12 +legato +rjump layer_4A34 +end + +.channel enemy_boss_twinrova_ice_charge +instr FONT01_INSTR_WIND +ldlayer 0, layer_4A56 +vibfreq 127 +vibdepth 84 +end + +.layer layer_4A56 +legato +portamento 0x85, 35, 120 +notedv PITCH_AF5, 0xC8, 100 +.layer layer_4A5F +notedv PITCH_AF5, 30000, 100 +rjump layer_4A5F + +.channel enemy_ganondorf_charge_major +instr FONT01_INSTR_WIND +ldlayer 0, layer_4A94 +ldlayer 1, layer_4A96 +ldlayer 2, layer_4A9E +vibfreq 175 +vibdepth 196 +ldi 36 +stio 6 +ldi 191 +call delay_varyingvol +.channel chan_4A7C +ldio 6 +stseq 0, layer_4AAA+1 +stseq 0, layer_4AAD+1 +sub 1 +stio 6 +sub 4 +rbeqz chan_4A93 +ldi 8 +call delay_varyingvol +rjump chan_4A7C +.channel chan_4A93 +end + +.layer layer_4A94 +instr FONT01_INSTR_DINO_INHALE + +.layer layer_4A96 +env envelope_68B4, 249 +transpose -4 +rjump layer_4A56 + +.layer layer_4A9E +instr FONT01_INSTR_DODONGO_ROAR +ldelay 0x120 +loop 10 +legato +portamento 0x85, 27, 255 +.layer layer_4AAA +notedv PITCH_F3, 0x1E, 100 +.layer layer_4AAD +notedv PITCH_A2, 0x1E, 100 +nolegato +loopend +end + +.channel enemy_boss_twinrova_cast +instr 2 +ldlayer 0, layer_4ABF +gain 20 +vibfreq 144 +vibdepth 240 +end + +.layer layer_4ABF +notedv PITCH_AF2, 0x30, 100 +end + +.channel enemy_darunia_chest_pound +instr FONT01_INSTR_SMASH +ldlayer 0, layer_4AC9 +end + +.layer layer_4AC9 +env envelope_68DC, 250 +.layer layer_4ACD +portamento 0x81, 26, 64 +notedv PITCH_E2, 0xC, 100 +rjump layer_4ACD + +.channel enemy_darunia_head_pat +instr FONT01_INSTR_SMASH +env envelope_692C +ldlayer 0, layer_4ADF +end + +.layer layer_4ADF +portamento 0x81, 32, 130 +notedv PITCH_GF2, 0x1E, 100 +end + +.channel enemy_boss_twinrova_hurt_cry_old +ldlayer 0, layer_4261 +ldlayer 1, layer_4AEE +end + +.layer layer_4AEE +instr FONTANY_INSTR_SFX +notedv FONT01_EFFECT_WITCH_HURT, 0x0, 100 +end + +.channel enemy_boss_twinrova_hit_beam_young +ldlayer 0, layer_4261 +ldlayer 1, layer_4AFB +end + +.layer layer_4AFB +instr FONTANY_INSTR_SFX +notedv FONT01_EFFECT_WITCH_SHOCK, 0x0, 100 +end + +.channel enemy_boss_twinrova_die_young +ldlayer 0, layer_4B0B +ldlayer 1, layer_4B12 +ldlayer 2, layer_4829 +end + +.layer layer_4B0B +instr FONT01_INSTR_THUNDERBURST +notedv PITCH_AF4, 0x110, 100 +end + +.layer layer_4B12 +instr FONTANY_INSTR_SFX +notedv FONT01_EFFECT_TWINROVA_SCREAM, 0x0, 100 +end + +.channel enemy_boss_twinrova_spirit_fly +instr FONT01_INSTR_DODONGO_ROAR +ldlayer 0, layer_4B22 +vibfreq 112 +vibdepth 128 +end + +.layer layer_4B22 +env envelope_69DC, 240 +legato +portamento 0x85, 3, 255 +notedv PITCH_F2, 0x1A, 100 +notedv PITCH_A0, 0x20, 100 +end + +.layer layer_4B32 +instr FONTANY_INSTR_8PULSE +env envelope_6A7C, 249 +.layer layer_4B38 +notedv PITCH_GF3, 30000, 100 +rjump layer_4B38 + +.channel enemy_boss_twinrova_charge +ldlayer 0, layer_521B +ldlayer 1, layer_5219 +vibfreq 96 +vibdepth 240 +end + +.channel enemy_knuckle_walk +ldlayer 0, layer_4B59 +ldlayer 1, layer_4B50 +end + +.layer layer_4B50 +instr FONT01_INSTR_SLIDE_BOOTS +notedv PITCH_BF1, 0x8, 64 +notedv PITCH_G2, 0x14, 64 +end + +.layer layer_4B59 +instr FONT01_INSTR_GUNSHOT +env envelope_68DC, 249 +portamento 0x81, 26, 96 +notedv PITCH_DF2, 0x1E, 100 +end + +.channel enemy_knuckle_attack +ldlayer 0, layer_4B71 +ldlayer 1, layer_4B7B +ldlayer 2, layer_4B87 +end + +.layer layer_4B71 +instr FONT01_INSTR_GERUDO_ATTACK +portamento 0x81, 27, 255 +notedv PITCH_A2, 0x78, 100 +end + +.layer layer_4B7B +instr FONT01_INSTR_SLIDE_BOOTS +notedv PITCH_BF1, 0x4, 64 +notedv PITCH_G2, 0x6, 64 +notedv PITCH_DF3, 0x14, 64 +end + +.layer layer_4B87 +instr FONTANY_INSTR_SFX +notedv FONT01_EFFECT_KNUCKLE_ATTACK, 0x0, 100 +end + +.channel enemy_bubble_die +ldlayer 0, layer_4B9B +ldlayer 2, layer_4BA9 +.channel chan_4B93 +ldlayer 1, layer_4829 +vibfreq 128 +vibdepth 48 +end + +.layer layer_4B9B +instr FONT01_INSTR_PHANTOM_MOAN +legato +portamento 0x85, 46, 200 +notedv PITCH_C5, 0x20, 100 +notedv PITCH_E4, 0x6C, 100 +end + +.layer layer_4BA9 +instr FONT01_INSTR_POT_BREAK +notedv PITCH_G3, 0x5, 100 +notedv PITCH_G3, 0x5, 100 +end + +.channel enemy_bubble_hurt +ldlayer 0, layer_4BB7 +rjump chan_4B93 + +.layer layer_4BB7 +transpose 5 +rjump layer_4B9B +end + +.channel enemy_bubble_attack +ldlayer 0, layer_4BC0 +end + +.layer layer_4BC0 +instr FONT01_INSTR_STALFOS_ATTACK +legato +portamento 0x85, 30, 30 +notedv PITCH_AF4, 0x8, 100 +notedv PITCH_GF4, 0x12, 100 +end + +.channel enemy_poe_sister_die +ldlayer 3, layer_4829 +.channel chan_4BD1 +ldlayer 0, layer_4BDB +ldlayer 1, layer_4BDD +ldlayer 2, layer_4BF3 +end + +.layer layer_4BDB +ldelay 0x8 + +.layer layer_4BDD +instr FONT01_INSTR_PHANTOM_LAUGH_1 +transpose 12 +portamento 0x81, 48, 100 +notedv PITCH_E5, 0x1E, 100 +portamento 0x85, 51, 100 +notedv PITCH_F5, 0x14, 100 +notedv PITCH_B4, 0x1E, 100 +end + +.layer layer_4BF3 +instr FONT01_INSTR_PHANTOM_GROWL +legato +transpose 48 +portamento 0x85, 47, 200 +notedv PITCH_D5, 0x20, 100 +notedv PITCH_B2, 0x64, 100 +end + +.channel enemy_big_poe_get_soul +rjump chan_4BD1 + +.channel enemy_knuckle_clank +ldlayer 0, layer_4B7B +end + +.channel enemy_bari_spin +instr FONT01_INSTR_GERUDO_ATTACK +ldlayer 0, layer_4C0F +end + +.layer layer_4C0F +legato +portamento 0x85, 19, 200 +notedv PITCH_EF2, 0x18, 100 +notedv PITCH_B2, 0x3C, 100 +end + +.channel enemy_larvae_paralyzed +instr FONT01_INSTR_POE_DISAPPEAR +ldlayer 0, layer_4C25 +vibfreq 196 +vibdepth 196 +end + +.layer layer_4C25 +portamento 0x81, 62, 255 +notedv PITCH_EF3, 0x40, 100 +end + +.channel enemy_bari_die +ldlayer 0, layer_4C34 +ldlayer 1, layer_4829 +end + +.layer layer_4C34 +instr FONT01_INSTR_GUAY_HURT +.layer layer_4C36 +portamento 0x81, 32, 255 +notedv PITCH_C4, 0xA, 100 +portamento 0x81, 34, 255 +notedv PITCH_D4, 0xA, 100 +portamento 0x81, 36, 255 +notedv PITCH_E4, 0xA, 100 +portamento 0x81, 45, 255 +notedv PITCH_A3, 0xE, 100 +end + +.channel enemy_bari_split +ldlayer 0, layer_4C57 +end + +.layer layer_4C57 +instr FONT01_INSTR_GULP_SPEAR +transpose 4 +rjump layer_4C36 + +.channel enemy_floormaster_attack +instr FONT01_INSTR_DODONGO_ROAR +ldlayer 0, layer_4C6A +env envelope_699C +vibfreq 112 +vibdepth 96 +end + +.layer layer_4C6A +notedv PITCH_E2, 0x64, 100 +end + +.channel enemy_floormaster_mini_walk +instr FONT01_INSTR_EGG_CRACK +ldlayer 0, layer_4C74 +end + +.layer layer_4C74 +portamento 0x81, 21, 128 +notedv PITCH_A2, 0x8, 100 +end + +.channel enemy_floormaster_mini_die +instr FONT01_INSTR_DINO_ROAR +ldlayer 0, layer_4C89 +ldlayer 1, layer_4829 +vibfreq 132 +vibdepth 70 +end + +.layer layer_4C89 +legato +portamento 0x85, 56, 128 +notedv PITCH_BF5, 0x14, 100 +notedv PITCH_D5, 0x2C, 100 +end + +.channel enemy_floormaster_mini_grow +instr FONT01_INSTR_DINO_ROAR +ldlayer 0, layer_4CA2 +env envelope_69DC +vibfreq 62 +vibdepth 96 +end + +.layer layer_4CA2 +notedv PITCH_AF3, 0x3C, 80 +rjump layer_4CA2 + +.channel enemy_floormaster_grow_done +ldlayer 0, layer_4CAB +end + +.layer layer_4CAB +instr FONT01_INSTR_EXPLOSION_LAVA +env envelope_694C, 249 +legato +portamento 0x85, 7, 150 +notedv PITCH_DF1, 0xA, 100 +notedv PITCH_DF2, 0x16, 100 +end + +.channel enemy_floormaster_split +ldlayer 0, layer_4CC1 +end + +.layer layer_4CC1 +transpose 12 +rjump layer_4CAB +end + +.channel enemy_floormaster_mini_grab +instr FONT01_INSTR_DINO_ROAR +ldlayer 0, layer_4CD3 +env envelope_69FC +vibfreq 80 +vibdepth 64 +end + +.layer layer_4CD3 +legato +portamento 0x85, 6, 255 +notedv PITCH_EF3, 0x2A, 69 +notedv PITCH_G2, 0x40, 69 +rjump layer_4CD3 + +.channel enemy_floormaster_mini_land +instr FONT01_INSTR_SMASH +ldlayer 0, layer_4CE6 +end + +.layer layer_4CE6 +legato +env envelope_68FC, 255 +portamento 0x85, 25, 230 +notedv PITCH_EF3, 0x5, 80 +notedv PITCH_BF2, 0x5, 80 +nolegato +ldelay 0x5 +legato +env envelope_68FC, 255 +portamento 0x85, 25, 220 +notedv PITCH_EF3, 0x5, 80 +notedv PITCH_BF2, 0xA, 80 +end + +.channel enemy_cucco_flap +instr FONT01_INSTR_OWL_FLAP +ldlayer 0, layer_4D0E +end + +.layer layer_4D0E +portamento 0x81, 35, 200 +notedv PITCH_B3, 0x20, 100 +end + +.channel enemy_ganondorf_magic_fire +ldlayer 0, layer_4D23 +ldlayer 1, layer_4A09 +ldlayer 2, layer_4A0B +ldlayer 3, layer_4A17 +end + +.layer layer_4D23 +ldelay 0x7F +end + +.channel enemy_floormaster_slide +instr FONT01_INSTR_SLIDE_BOOTS +ldlayer 0, layer_4D2C +end + +.layer layer_4D2C +transpose 48 +.layer layer_4D2E +notedv PITCH_C4, 30000, 100 +rjump layer_4D2E + +.channel enemy_knuckle_armor_rebound2 +ldlayer 0, layer_4D4D +ldlayer 1, layer_4D3B +end + +.layer layer_4D3B +instr FONT01_INSTR_SLIDE_BOOTS +notedv PITCH_GF1, 0x40, 100 +notedv PITCH_GF1, 0x14, 100 +notedv PITCH_GF1, 0x10, 84 +notedv PITCH_GF1, 0xA, 68 +notedv PITCH_GF1, 0xA, 68 +end + +.layer layer_4D4D +transpose -8 +ldelay 0x4 +rjump layer_4D3B + +.channel enemy_knuckle_armor_rebound3 +ldlayer 0, layer_4D3B +end + +.channel enemy_knuckle_armor_rebound1 +ldlayer 0, layer_4D70 +ldlayer 1, layer_4D5E +end + +.layer layer_4D5E +instr FONT01_INSTR_SLIDE_BOOTS +notedv PITCH_GF1, 0x8, 100 +notedv PITCH_GF1, 0x40, 100 +notedv PITCH_GF1, 0x20, 100 +notedv PITCH_GF1, 0x30, 84 +notedv PITCH_GF1, 0x40, 68 +end + +.layer layer_4D70 +transpose -8 +rjump layer_4D5E + +.channel enemy_knuckle_stagger +ldlayer 0, layer_4D87 +ldlayer 1, layer_4D7B +end + +.layer layer_4D7B +instr FONT01_INSTR_SLIDE_BOOTS +notedv PITCH_EF1, 0x6, 100 +notedv PITCH_GF1, 0xE, 100 +notedv PITCH_C2, 0x10, 100 +end + +.layer layer_4D87 +transpose -5 +rjump layer_4D7B + +.channel enemy_knucle_armor_loss +ldlayer 0, layer_4D9C +ldlayer 1, layer_4D92 +end + +.layer layer_4D92 +instr FONT01_INSTR_POT_BREAK +portamento 0x81, 8, 200 +notedv PITCH_BF1, 0x20, 100 +end + +.layer layer_4D9C +instr FONT01_INSTR_SLIDE_BOOTS +ldelay 0xE +notedv PITCH_EF1, 0x14, 64 +end + +.channel enemy_knuckle_warcry +ldlayer 0, layer_4DAB +ldlayer 1, layer_4DBB +end + +.layer layer_4DAB +instr FONT01_INSTR_SLIDE_BOOTS +env envelope_695C, 249 +loop 5 +notedv PITCH_C2, 0xA, 100 +notedv PITCH_G1, 0x8, 100 +loopend +end + +.layer layer_4DBB +instr FONTANY_INSTR_SFX +notedv FONT01_EFFECT_KNUCKLE_CHARGE, 0x0, 100 +end + +.channel enemy_knuckle_snap +ldlayer 0, layer_4DC7 +gain 32 +end + +.layer layer_4DC7 +instr FONTANY_INSTR_SFX +notedv FONT01_EFFECT_SNAP, 0x0, 100 +end + +.channel enemy_boss_barinade_pulse +instr FONT01_INSTR_BOULDER +ldlayer 0, layer_4DDA +ldlayer 1, layer_4DDC +vibfreq 40 +vibdepth 96 +end + +.layer layer_4DDA +transpose 6 + +.layer layer_4DDC +notedv PITCH_A4, 30000, 100 +rjump layer_4DDC + +.channel enemy_boss_barinade_hurt +ldlayer 0, layer_4E03 +ldlayer 1, layer_4DF3 +ldlayer 2, layer_4DF5 +ldlayer 3, layer_4829 +vibfreq 116 +vibdepth 210 +end + +.layer layer_4DF3 +transpose 12 + +.layer layer_4DF5 +instr FONT01_INSTR_DINO_ROAR +.layer layer_4DF7 +portamento 0x85, 32, 255 +notedv PITCH_C4, 0x20, 80 +notedv PITCH_B2, 0x90, 80 +end + +.layer layer_4E03 +instr FONT01_INSTR_MONSTER_ROAR +portamento 0x81, 37, 100 +notedv PITCH_GF2, 0xB0, 100 +end + +.channel enemy_tentacle_die +ldlayer 0, layer_4E1F +ldlayer 1, layer_4DF5 +ldlayer 2, layer_4E77 +ldlayer 3, layer_4829 +vibfreq 80 +vibdepth 48 +end + +.layer layer_4E1F +transpose 4 +rjump layer_4E03 + +.channel enemy_boss_barinade_weak_hurt +ldlayer 0, layer_4E3A +ldlayer 1, layer_4E34 +ldlayer 2, layer_4E36 +ldlayer 3, layer_4829 +vibfreq 164 +vibdepth 162 +end + +.layer layer_4E34 +transpose 4 + +.layer layer_4E36 +instr FONT01_INSTR_DODONGO_ROAR +rjump layer_4DF7 + +.layer layer_4E3A +transpose 2 +rjump layer_4E03 + +.channel enemy_boss_barinade_die +ldlayer 0, layer_4E47 +ldlayer 1, layer_4E45 +end + +.layer layer_4E45 +transpose 6 + +.layer layer_4E47 +instr FONT01_INSTR_EXPLOSION_LAVA +env envelope_694C, 249 +legato +portamento 0x85, 19, 150 +notedv PITCH_C1, 0xA, 100 +notedv PITCH_B2, 0x14, 100 +end + +.channel enemy_boss_twinrova_hurt +ldlayer 0, layer_4E75 +ldlayer 1, layer_4E77 +ldlayer 2, layer_4E66 +ldlayer 3, layer_4E68 +end + +.layer layer_4E66 +transpose 2 + +.layer layer_4E68 +instr FONT01_INSTR_EXPLOSION_LAVA +portamento 0x85, 34, 255 +notedv PITCH_F4, 0x14, 100 +notedv PITCH_B2, 0x7F, 100 +end + +.layer layer_4E75 +transpose -2 + +.layer layer_4E77 +instr FONT01_INSTR_PHANTOM_WAIL +legato +portamento 0x85, 39, 64 +notedv PITCH_F4, 0x12, 100 +notedv PITCH_A3, 0xA8, 100 +end + +.channel enemy_boss_barinade_tentacle_break +ldlayer 0, layer_4E66 +ldlayer 1, layer_4E68 +end + +.channel enemy_boss_barinade_bari_attach +ldlayer 0, layer_4E94 +ldlayer 1, layer_4E9E +end + +.layer layer_4E94 +instr FONT01_INSTR_BABA_LUNGE +portamento 0x81, 35, 50 +notedv PITCH_AF2, 0x30, 100 +end + +.layer layer_4E9E +instr FONT01_INSTR_GANONDORF_ATTACK_0 +portamento 0x81, 39, 50 +notedv PITCH_DF3, 0x40, 100 +end + +.channel enemy_boss_barinade_beam +instr FONT01_INSTR_THUNDERBURST +ldlayer 0, layer_4EB7 +ldlayer 1, layer_4EB5 +vibfreq 196 +vibdepth 48 +end + +.layer layer_4EB5 +transpose 8 + +.layer layer_4EB7 +notedv PITCH_A3, 0x1A2, 100 +end + +.channel enemy_deadhand_grab +instr FONT01_INSTR_GERUDO_ATTACK +ldlayer 0, layer_4EC6 +vibfreq 128 +vibdepth 160 +end + +.layer layer_4EC6 +portamento 0x81, 22, 255 +notedv PITCH_DF2, 0x7F, 100 +end + +.channel enemy_tentacle_wind_up +instr FONT01_INSTR_GERUDO_ATTACK +ldlayer 0, layer_4ED8 +vibfreq 128 +vibdepth 160 +end + +.layer layer_4ED8 +portamento 0x81, 16, 255 +notedv PITCH_G2, 0x7F, 100 +end + +.channel enemy_shabom_pop +ldlayer 0, layer_4EF4 +ldlayer 1, layer_4EEA +ldlayer 2, layer_4EF9 +end + +.layer layer_4EEA +instr FONT01_INSTR_GUNSHOT +portamento 0x81, 54, 100 +notedv PITCH_B5, 0x60, 100 +end + +.layer layer_4EF4 +ldelay 0x2 +rjump layer_4EEA +end + +.layer layer_4EF9 +instr FONT01_INSTR_STEP_WATER +portamento 0x81, 27, 255 +notedv PITCH_F3, 0x14, 100 +end + +.channel enemy_shabom_bounce +instr FONT01_INSTR_WATER_BUBBLES +ldlayer 0, layer_4F0C +env envelope_692C +end + +.layer layer_4F0C +portamento 0x85, 39, 100 +notedv PITCH_A3, 0x16, 100 +notedv PITCH_B4, 0x16, 100 +end + +.channel enemy_stinger_submerge +instr FONT01_INSTR_WATER_SPLASH_L +ldlayer 0, layer_4F20 +env envelope_68CC +end + +.layer layer_4F20 +portamento 0x81, 27, 100 +notedv PITCH_F3, 0x34, 100 +end + +.channel enemy_stinger_glide +instr FONT01_INSTR_DINO_ROAR +ldlayer 0, layer_4F32 +vibfreq 80 +vibdepth 96 +end + +.layer layer_4F32 +env envelope_6A2C, 230 +.layer layer_4F36 +notedv PITCH_E2, 0xD0, 80 +rjump layer_4F36 + +.channel enemy_stinger_attack +ldlayer 0, layer_4F44 +vibfreq 240 +vibdepth 160 +end + +.layer layer_4F44 +instr FONT01_INSTR_GUAY_HURT +portamento 0x81, 52, 255 +notedv PITCH_GF5, 0x40, 100 +end + +.channel enemy_stinger_cry +ldlayer 0, layer_4F55 +ldlayer 1, layer_4F57 +end + +.layer layer_4F55 +ldelay 0x6 + +.layer layer_4F57 +instr FONT01_INSTR_GUAY_HURT +notedv PITCH_GF5, 0x64, 100 +end + +.channel enemy_boss_bongo_drum_low +instr FONT01_INSTR_BONGO_BONGO +ldlayer 0, layer_4F6A +ldlayer 1, layer_4F68 +gain 24 +end + +.layer layer_4F68 +transpose 2 + +.layer layer_4F6A +notedv PITCH_C4, 0x40, 100 +end + +.channel enemy_boss_bongo_drum_high +instr FONT01_INSTR_BONGO_BONGO +ldlayer 0, layer_4F7B +ldlayer 1, layer_4F79 +gain 24 +end + +.layer layer_4F79 +transpose 2 + +.layer layer_4F7B +notedv PITCH_F4, 0x40, 100 +end + +.channel enemy_owl_fly +instr FONT01_INSTR_OWL_FLAP +ldlayer 0, layer_4F8A +ldlayer 1, layer_4F88 +end + +.layer layer_4F88 +transpose 2 + +.layer layer_4F8A +portamento 0x81, 23, 200 +notedv PITCH_B2, 0x2C, 100 +end + +.channel enemy_peahat_fly +instr FONT01_INSTR_SWOOSH +ldlayer 0, layer_4F98 +end + +.layer layer_4F98 +notedv PITCH_E5, 0x6, 100 +notedv PITCH_GF5, 0x6, 100 +notedv PITCH_AF5, 0x6, 100 +notedv PITCH_A5, 0x6, 100 +notedv PITCH_AF5, 0x6, 100 +notedv PITCH_GF5, 0x6, 100 +notedv PITCH_E5, 0x6, 100 +rjump layer_4F98 + +.channel enemy_peahat_land +instr FONT01_INSTR_SMASH +ldlayer 0, layer_361B +end + +.channel enemy_peahat_rise +instr FONT01_INSTR_SMASH +ldlayer 0, layer_4FBB +end + +.layer layer_4FBB +portamento 0x81, 15, 104 +notedv PITCH_B3, 0x40, 100 +end + +.channel enemy_peahat_hurt +ldlayer 0, layer_4FDE +ldlayer 1, layer_4FD1 +ldlayer 2, layer_4829 +vibfreq 112 +vibdepth 160 +end + +.layer layer_4FD1 +instr FONT01_INSTR_DINO_ROAR +portamento 0x85, 40, 255 +notedv PITCH_AF4, 0x20, 80 +notedv PITCH_G3, 0x40, 80 +end + +.layer layer_4FDE +instr FONT01_INSTR_MONSTER_ROAR +portamento 0x81, 41, 100 +notedv PITCH_EF3, 0x60, 100 +end + +.channel enemy_boss_twinrova_fly +instr FONT01_INSTR_DODONGO_ROAR +ldlayer 0, layer_4FF2 +vibfreq 96 +vibdepth 128 +end + +.layer layer_4FF2 +env envelope_6A2C, 230 +.layer layer_4FF6 +notedv PITCH_GF1, 0x70, 100 +rjump layer_4FF6 + +.channel enemy_boss_twinrova_hover +ldlayer 0, layer_5008 +ldlayer 1, layer_5006 +vibfreq 16 +vibdepth 128 +end + +.layer layer_5006 +transpose 2 + +.layer layer_5008 +instr FONT01_INSTR_DODONGO_ROAR +env envelope_6A2C, 230 +.layer layer_500E +notedv PITCH_C1, 0x70, 100 +rjump layer_500E + +.channel enemy_tektite_jump_water +instr FONT01_INSTR_WATER_SPLASH_L +ldlayer 0, layer_5019 +end + +.layer layer_5019 +portamento 0x81, 35, 100 +notedv PITCH_DF5, 0x38, 80 +end + +.channel enemy_tektite_land_water2 +instr FONT01_INSTR_WATER_SPLASH_L +ldlayer 0, layer_5027 +end + +.layer layer_5027 +portamento 0x81, 49, 100 +notedv PITCH_EF4, 0x38, 80 +end + +.channel enemy_tektite_turn_water +instr FONT01_INSTR_STEP_WATER +ldlayer 0, layer_5035 +end + +.layer layer_5035 +portamento 0x81, 16, 100 +notedv PITCH_E2, 0x30, 68 +end + +.channel enemy_blob_wave +instr FONT01_INSTR_DINO_INHALE +ldlayer 0, layer_5047 +vibfreq 112 +vibdepth 240 +end + +.layer layer_5047 +transpose -19 +legato +portamento 0x85, 0, 255 +notedv PITCH_A2, 0x20, 100 +notedv PITCH_A0, 0x20, 100 +end + +.channel enemy_boss_bongo_clap +ldlayer 0, layer_505C +ldlayer 1, layer_505E +end + +.layer layer_505C +transpose -6 + +.layer layer_505E +instr FONT01_INSTR_GUNSHOT +notedv PITCH_D5, 0x30, 100 +end + +.channel enemy_boss_bongo_hand_wave +instr FONT01_INSTR_THUNDERBURST +ldlayer 0, layer_506E +vibfreq 128 +vibdepth 224 +end + +.layer layer_506E +notedv PITCH_F3, 0x35, 100 +end + +.channel enemy_boss_bongo_hand_attack +instr FONT01_INSTR_DODONGO_ROAR +ldlayer 0, layer_5083 +ldlayer 1, layer_5081 +releaserate 220 +vibfreq 112 +vibdepth 96 +end + +.layer layer_5081 +transpose 6 + +.layer layer_5083 +notedv PITCH_E2, 0x90, 100 +rjump layer_5083 + +.channel enemy_wallmaster_grab +ldlayer 0, layer_5095 +ldlayer 1, layer_5093 +ldlayer 2, layer_50A3 +end + +.layer layer_5093 +transpose 2 + +.layer layer_5095 +instr FONT01_INSTR_SMASH +env envelope_696C, 250 +portamento 0x81, 19, 50 +notedv PITCH_E1, 0x20, 100 +end + +.layer layer_50A3 +instr FONT01_INSTR_EGG_CRACK +env envelope_696C, 250 +portamento 0x81, 15, 50 +notedv PITCH_A1, 0x20, 100 +end + +.channel enemy_boss_bongo_hand_shake +instr FONT01_INSTR_OWL_FLAP +ldlayer 0, layer_50B7 +end + +.layer layer_50B7 +portamento 0x85, 21, 200 +notedv PITCH_D3, 0x13, 100 +notedv PITCH_GF2, 0x13, 100 +end + +.channel enemy_boss_bongo_hurt +ldlayer 0, layer_50D3 +ldlayer 1, layer_4524 +ldlayer 2, layer_4532 +ldlayer 3, layer_4829 +vibfreq 48 +vibdepth 48 +end + +.layer layer_50D3 +instr FONT01_INSTR_SCRUB_DEATH +legato +portamento 0x85, 4, 60 +notedv PITCH_D2, 0x32, 100 +notedv PITCH_AF1, 0x7F, 100 +end + +.channel enemy_boss_bongo_hand_hurt +ldlayer 0, layer_50D3 +vibfreq 48 +vibdepth 48 +end + +.channel enemy_boss_bongo_vanish +instr FONT01_INSTR_POE_DISAPPEAR +ldlayer 0, layer_50F8 +ldlayer 1, layer_50F6 +vibfreq 96 +vibdepth 80 +end + +.layer layer_50F6 +transpose 6 + +.layer layer_50F8 +portamento 0x81, 27, 255 +notedv PITCH_C2, 0x118, 100 +end + +.channel enemy_beamos_beam +instr FONTANY_INSTR_BELL +ldlayer 0, layer_510B +vibfreq 128 +vibdepth 116 +end + +.layer layer_510B +notedv PITCH_F4, 30000, 64 +rjump layer_510B + +.channel enemy_beamos_idle +instr FONT01_INSTR_BABA_LUNGE +ldlayer 0, layer_511B +vibfreq 208 +vibdepth 96 +end + +.layer layer_511B +notedv PITCH_F1, 30000, 64 +rjump layer_511B + +.channel enemy_beamos_ground_hit +instr FONT01_INSTR_DINO_INHALE +ldlayer 0, layer_5127 +end + +.layer layer_5127 +notedv PITCH_DF1, 30000, 100 +rjump layer_5127 + +.channel enemy_beamos_charging +ldlayer 0, layer_45DF +vibfreq 160 +vibdepth 160 +end + +.channel enemy_tektite_flip +instr FONT01_INSTR_WATER_BUBBLES +ldlayer 0, layer_5142 +ldlayer 1, layer_5144 +vibfreq 176 +vibdepth 160 +end + +.layer layer_5142 +transpose -5 + +.layer layer_5144 +portamento 0x85, 39, 100 +notedv PITCH_E3, 0x10, 100 +notedv PITCH_DF5, 0x13, 100 +end + +.channel enemy_torch_slug_crawl +ldlayer 0, layer_5160 +ldlayer 1, layer_5156 +end + +.layer layer_5156 +instr FONT01_INSTR_EGG_CRACK +portamento 0x81, 8, 255 +notedv PITCH_C2, 0x40, 100 +end + +.layer layer_5160 +ldelay 0x8 +rjump layer_5156 + +.channel enemy_torch_slug_target +ldlayer 0, layer_516C +vibfreq 64 +vibdepth 96 +end + +.layer layer_516C +instr FONT01_INSTR_DINO_ROAR +legato +portamento 0x85, 39, 255 +notedv PITCH_D4, 0x8, 100 +notedv PITCH_A3, 0x20, 100 +end + +.channel enemy_torch_slug_die +ldlayer 0, layer_5188 +ldlayer 1, layer_418B +ldlayer 2, layer_4829 +vibfreq 64 +vibdepth 192 +end + +.layer layer_5188 +instr FONT01_INSTR_DINO_ROAR +legato +portamento 0x85, 25, 255 +notedv PITCH_GF3, 0x14, 80 +notedv PITCH_GF2, 0x60, 80 +end + +.channel enemy_tile_fly +instr FONT01_INSTR_SWOOSH +ldlayer 0, layer_519C +end + +.layer layer_519C +loop 6 +notedv PITCH_C5, 0x9, 100 +notedv PITCH_D5, 0x9, 100 +notedv PITCH_E5, 0x9, 100 +loopend + +.layer layer_51A8 +env envelope_697C, 255 +.layer layer_51AC +notedv PITCH_GF5, 0x6, 100 +notedv PITCH_AF5, 0x6, 100 +notedv PITCH_BF5, 0x6, 100 +notedv PITCH_AF5, 0x6, 100 +rjump layer_51AC + +.channel enemy_firedancer_kick +instr 2 +ldlayer 0, layer_51C0 +end + +.layer layer_51C0 +notedv PITCH_A2, 0x30, 100 +end + +.channel enemy_firedancer_spin +ldlayer 0, layer_51CB +ldlayer 1, layer_51D9 +end + +.layer layer_51CB +instr FONT01_INSTR_BOULDER +.layer layer_51CD +transpose 12 +env envelope_6A7C, 224 +.layer layer_51D3 +notedv PITCH_C5, 30000, 100 +rjump layer_51D3 + +.layer layer_51D9 +instr FONT01_INSTR_GANONDORF_FLY +rjump layer_51CD + +.channel enemy_firehead_run +instr FONT01_INSTR_SMASH +ldlayer 0, layer_51E3 +end + +.layer layer_51E3 +portamento 0x81, 20, 64 +notedv PITCH_BF1, 0xD, 100 +end + +.channel enemy_firehead_hurt +ldlayer 0, layer_51F6 +ldlayer 1, layer_4829 +vibfreq 64 +vibdepth 208 +end + +.layer layer_51F6 +instr FONT01_INSTR_PHANTOM_WAIL +legato +portamento 0x85, 47, 100 +notedv PITCH_F5, 0x14, 100 +notedv PITCH_AF4, 0x24, 100 +end + +.channel enemy_firedancer_hurt +ldlayer 0, layer_4301 +end + +.channel enemy_firedancer_laugh +ldlayer 0, layer_521B +ldlayer 1, layer_5219 +ldlayer 2, layer_5226 +ldlayer 3, layer_5228 +vibfreq 48 +vibdepth 32 +end + +.layer layer_5219 +transpose 2 + +.layer layer_521B +instr 2 +portamento 0x81, 21, 255 +notedv PITCH_B4, 0xE0, 100 +end + +.layer layer_5226 +transpose 1 + +.layer layer_5228 +instr FONT01_INSTR_PHANTOM_LAUGH_1 +notedv PITCH_F4, 0xE0, 100 +end + +.channel enemy_moblin_club_shockwave +instr FONT01_INSTR_DINO_INHALE +ldlayer 0, layer_523A +ldlayer 1, layer_523C +releaserate 224 +end + +.layer layer_523A +transpose -6 + +.layer layer_523C +notedv PITCH_GF2, 30000, 100 +rjump layer_523C + +.channel enemy_peahat_jr_fly +instr FONT01_INSTR_SWOOSH +ldlayer 0, layer_524B +env envelope_697C +end + +.layer layer_524B +notedv PITCH_GF5, 0x6, 80 +notedv PITCH_AF5, 0x6, 80 +notedv PITCH_BF5, 0x6, 80 +notedv PITCH_AF5, 0x6, 80 +rjump layer_524B + +.channel enemy_boss_bongo_paralyze +ldlayer 0, layer_4524 +ldlayer 1, layer_4532 +vibfreq 48 +vibdepth 48 +end + +.channel enemy_boss_bongo_die +ldlayer 0, layer_5277 +ldlayer 1, layer_5275 +ldlayer 2, layer_5286 +ldlayer 3, layer_4829 +vibfreq 70 +vibdepth 86 +end + +.layer layer_5275 +transpose 2 + +.layer layer_5277 +instr FONT01_INSTR_MONSTER_ROAR +.layer layer_5279 +legato +portamento 0x85, 27, 127 +notedv PITCH_A3, 0x28, 100 +notedv PITCH_E3, 0xC8, 100 +end + +.layer layer_5286 +instr FONT01_INSTR_THUNDER_HURT +transpose 12 +rjump layer_5279 + +.channel enemy_boss_bongo_dissipate +ldlayer 0, layer_529A +ldlayer 1, layer_52A6 +ldlayer 2, layer_52A8 +vibfreq 20 +vibdepth 20 +end + +.layer layer_529A +instr FONT01_INSTR_DINO_INHALE +.layer layer_529C +env envelope_6A7C, 200 +.layer layer_52A0 +notedv PITCH_C2, 30000, 100 +rjump layer_52A0 + +.layer layer_52A6 +transpose -1 + +.layer layer_52A8 +instr 2 +rjump layer_529C + +.channel enemy_boss_bongo_charge +ldlayer 0, layer_52BC +ldlayer 1, layer_52C4 +ldlayer 2, layer_52BA +vibfreq 96 +vibdepth 84 +end + +.layer layer_52BA +transpose 4 + +.layer layer_52BC +instr FONT01_INSTR_DINO_INHALE +.layer layer_52BE +notedv PITCH_A2, 30000, 100 +rjump layer_52BE + +.layer layer_52C4 +instr FONT01_INSTR_BOULDER +.layer layer_52C6 +notedv PITCH_A4, 30000, 80 +rjump layer_52C6 + +.channel enemy_boss_bongo_chant +instr FONT01_INSTR_BONGO_BONGO +ldlayer 0, layer_52D2 +end + +.layer layer_52D2 +transpose 48 +notedv PITCH_BF2, 0xE0, 100 +end + +.channel enemy_like_like_die +ldlayer 0, layer_3FBA +ldlayer 1, layer_5188 +ldlayer 2, layer_4829 +vibfreq 64 +vibdepth 192 +end + +.channel enemy_leever_die +ldlayer 0, layer_3F78 +ldlayer 1, layer_400C +ldlayer 2, layer_4829 +vibfreq 112 +vibdepth 48 +end + +.channel enemy_gerudo_attack +ldlayer 0, layer_4081 +ldlayer 1, layer_52FC +end + +.layer layer_52FC +instr FONTANY_INSTR_SFX +notedv FONT01_EFFECT_GERUDO_ATTACK, 0x0, 80 +end + +.channel enemy_gerudo_hurt +ldlayer 0, layer_5309 +ldlayer 1, layer_4829 +end + +.layer layer_5309 +instr FONTANY_INSTR_SFX +notedv FONT01_EFFECT_GERUDO_HURT, 0x0, 100 +end + +.channel enemy_gerudo_defeat +ldlayer 0, layer_5316 +ldlayer 1, layer_4829 +end + +.layer layer_5316 +instr FONTANY_INSTR_SFX +notedv FONT01_EFFECT_GERUDO_DEFEAT, 0x0, 100 +end + +.channel enemy_wolfos_walk +ldlayer 0, layer_5320 +end + +.layer layer_5320 +instr FONT01_INSTR_SMASH +portamento 0x81, 44, 64 +notedv PITCH_GF3, 0x5, 72 +end + +.channel enemy_anubis_die +ldlayer 0, layer_5335 +ldlayer 1, layer_533C +vibfreq 56 +vibdepth 50 +end + +.layer layer_5335 +instr 2 +notedv PITCH_C3, 0xC8, 100 +end + +.layer layer_533C +instr FONT01_INSTR_PHANTOM_WAIL +legato +portamento 0x85, 32, 200 +notedv PITCH_D4, 0x10, 100 +notedv PITCH_EF3, 0x96, 100 +end + +.channel enemy_anubis_fire_hit +ldlayer 0, layer_534F +end + +.layer layer_534F +instr FONT01_INSTR_EXPLOSION_LAVA +legato +portamento 0x85, 30, 255 +notedv PITCH_B3, 0x20, 100 +notedv PITCH_E2, 0x50, 100 +end + +.channel enemy_destroyed_light_arrow +ldlayer 0, layer_5365 +vibfreq 208 +vibdepth 208 +end + +.layer layer_5365 +instr FONT01_INSTR_DINO_INHALE +legato +transpose 15 +portamento 0x85, 39, 239 +notedv PITCH_DF3, 0x18, 100 +notedv PITCH_B5, 0x38, 100 +end + +.channel enemy_freezard_hurt +ldlayer 0, layer_3A9A +ldlayer 1, layer_3962 +ldlayer 2, layer_4829 +end + +.channel enemy_freezard_die +ldlayer 0, layer_3A47 +ldlayer 1, layer_3962 +ldlayer 2, layer_4829 +end + +.channel enemy_deadhand_burrow +ldlayer 0, layer_538D +end + +.layer layer_538D +instr FONT01_INSTR_EXPLOSION_LAVA +env envelope_68B4, 220 +notedv PITCH_D4, 0x64, 100 +end + +.channel enemy_deadhand_laugh +instr FONT01_INSTR_PHANTOM_LAUGH_1 +ldlayer 0, layer_539F +gain 16 +end + +.layer layer_539F +portamento 0x81, 35, 239 +notedv PITCH_AF2, 0xE0, 100 +end + +.channel enemy_knuckle_armor_hurt +ldlayer 0, layer_53B3 +ldlayer 1, layer_4829 +vibfreq 224 +vibdepth 96 +end + +.layer layer_53B3 +instr FONT01_INSTR_SLIDE_BOOTS +notedv PITCH_A2, 0x40, 100 +end + +.channel enemy_knuckle_pillar_break +ldlayer 0, layer_53C0 +ldlayer 1, layer_53B3 +end + +.layer layer_53C0 +instr FONT01_INSTR_EXPLOSION_LAVA +notedv PITCH_AF3, 0x4, 100 +notedv PITCH_BF3, 0x4, 100 +notedv PITCH_DF4, 0x5, 100 +notedv PITCH_F4, 0x7, 100 +notedv PITCH_B3, 0x30, 100 +end + +.channel enemy_knuckle_stump_break +ldlayer 0, layer_53C0 +end + +.channel enemy_knuckle_axe_stuck +ldlayer 0, layer_364C +ldlayer 1, layer_53B3 +end + +.channel enemy_boss_ganon_attack +ldlayer 0, layer_4220 +ldlayer 1, layer_53E4 +end + +.layer layer_53E4 +instr FONT01_INSTR_ELECTRIC_ATTACK +notedv PITCH_B5, 0x5A, 70 +end + +.channel enemy_pot_fly +instr FONT01_INSTR_SWOOSH +ldlayer 0, layer_51A8 +end + +.channel enemy_ganondorf_vortex_charge +ldlayer 0, layer_5008 +ldlayer 1, layer_53FB +vibfreq 48 +vibdepth 240 +end + +.layer layer_53FB +instr FONT01_INSTR_DINO_INHALE +.layer layer_53FD +notedv PITCH_A2, 30000, 64 +rjump layer_53FD + +.channel enemy_boss_vocals +instr FONTANY_INSTR_SFX +ldio 4 +sub 176 +stseq 0, layer_5417 # set semitone = sound id - 176 +ldseq addr_541C +stseq 0, layer_5417+2 +ldlayer 0, layer_5417 +end + +.layer layer_5417 +notedvg 0, 0x0, 100, 0 +end + +.array addr_541C +byte 100 +byte 100 +byte 100 +byte 100 +byte 100 +byte 100 +byte 100 +byte 100 +byte 100 +byte 100 +byte 100 +byte 100 +byte 100 +byte 100 +byte 100 +byte 100 +byte 100 +byte 100 +byte 100 +byte 100 +byte 100 +byte 100 +byte 100 +byte 100 +byte 100 +byte 100 +byte 100 +byte 100 +byte 100 +byte 100 +byte 100 +byte 100 +byte 100 +byte 100 +byte 100 +byte 100 +byte 100 +byte 100 +byte 100 + +.channel enemy_ganondorf_throw_orb +ldlayer 0, layer_4220 +ldlayer 1, layer_4214 +end + +.channel enemy_ganondorf_hit_light +ldlayer 0, layer_434A +ldlayer 1, layer_434C +end + +.channel enemy_shell_open +ldlayer 0, layer_5458 +ldlayer 1, layer_5460 +end + +.layer layer_5458 +instr FONT01_INSTR_EGG_CRACK +ldelay 0x8 +notedv PITCH_G2, 0x25, 100 +end + +.layer layer_5460 +instr FONT01_INSTR_BABA_ATTACK +notedv PITCH_DF3, 0x2D, 100 +end + +.channel enemy_spike_trap_roll +instr FONT01_INSTR_SLIDE_BOOTS +ldlayer 0, layer_546C +end + +.layer layer_546C +notedv PITCH_EF2, 0xA, 50 +notedv PITCH_F2, 0xA, 50 +notedv PITCH_G2, 0xA, 50 +rjump layer_546C + +.channel enemy_stalkid_walk +ldlayer 0, layer_547B +end + +.layer layer_547B +instr FONT01_INSTR_EGG_CRACK +notedv PITCH_DF3, 0xE, 70 +end + +.channel enemy_stalkid_attack +ldlayer 0, layer_5488 +ldlayer 1, layer_4081 +end + +.layer layer_5488 +instr FONT01_INSTR_PHANTOM_LAUGH_1 +transpose 14 +notedv PITCH_C5, 0x30, 100 +end + +.channel enemy_boss_ganon_paralyze +ldlayer 0, layer_549E +ldlayer 1, layer_54A0 +ldlayer 2, layer_54AE +vibfreq 20 +vibdepth 50 +end + +.layer layer_549E +ldelay 0x14 + +.layer layer_54A0 +instr FONT01_INSTR_MONSTER_ROAR +.layer layer_54A2 +legato +portamento 0x85, 28, 255 +notedv PITCH_F2, 0x30, 100 +notedv PITCH_EF2, 0x48, 100 +end + +.layer layer_54AE +instr FONT01_INSTR_DINO_ROAR +transpose 4 +rjump layer_54A2 + +.channel enemy_boss_ganon_die +ldlayer 0, layer_54C5 +ldlayer 1, layer_54C7 +ldlayer 2, layer_54E9 +ldlayer 3, layer_54EB +vibfreq 20 +vibdepth 50 +end + +.layer layer_54C5 +ldelay 0xA + +.layer layer_54C7 +instr FONT01_INSTR_MONSTER_ROAR +loop 4 +portamento 0x81, 30, 107 +notedv PITCH_F4, 0x8C, 100 +.layer layer_54D3 +legato +portamento 0x85, 39, 255 +notedv PITCH_G4, 0x30, 100 +notedv PITCH_AF3, 0x48, 100 +nolegato +loopend +portamento 0x81, 35, 255 +notedv PITCH_BF2, 0xFA, 100 +end + +.layer layer_54E9 +ldelay 0xA + +.layer layer_54EB +instr FONT01_INSTR_DINO_ROAR +loop 4 +portamento 0x81, 44, 107 +notedv PITCH_A4, 0x8C, 100 +.layer layer_54F7 +legato +portamento 0x85, 47, 255 +notedv PITCH_BF4, 0x32, 100 +notedv PITCH_D4, 0x48, 100 +nolegato +loopend +portamento 0x81, 37, 255 +notedv PITCH_C3, 0xC8, 100 +end + +.channel enemy_boss_ganon_penultimate_hit +ldlayer 0, layer_551B +ldlayer 1, layer_551D +ldlayer 2, layer_5523 +vibfreq 20 +vibdepth 50 +end + +.layer layer_551B +ldelay 0xD + +.layer layer_551D +instr FONT01_INSTR_MONSTER_ROAR +loop 1 +rjump layer_54D3 + +.layer layer_5523 +instr FONT01_INSTR_DINO_ROAR +loop 1 +rjump layer_54F7 + +.channel enemy_wolfos_spawn +instr FONT01_INSTR_ANIMALS +ldlayer 0, layer_552F +end + +.layer layer_552F +portamento 0x81, 42, 40 +notedv PITCH_G4, 0x7F, 100 +end + +.channel enemy_wolfos_attack +ldlayer 0, layer_553E +ldlayer 1, layer_4081 +end + +.layer layer_553E +instr FONT01_INSTR_ANIMALS +portamento 0x81, 35, 72 +notedv PITCH_F4, 0x40, 100 +end + +.channel enemy_wolfos_hurt +instr FONT01_INSTR_ANIMALS +ldlayer 0, layer_5551 +ldlayer 1, layer_4829 +end + +.layer layer_5551 +legato +portamento 0x85, 39, 192 +notedv PITCH_F4, 0x20, 100 +notedv PITCH_DF4, 0x20, 100 +end + +.channel enemy_wolfos_die +instr FONT01_INSTR_ANIMALS +ldlayer 0, layer_5566 +ldlayer 1, layer_4829 +end + +.layer layer_5566 +legato +portamento 0x85, 39, 128 +notedv PITCH_B4, 0x1C, 100 +notedv PITCH_AF4, 0x60, 100 +end + +.channel enemy_wolfos_howl +instr FONT01_INSTR_ANIMALS +ldlayer 0, layer_5578 +end + +.layer layer_5578 +notedv PITCH_D4, 0x70, 75 +end + +.channel enemy_guay_hurt +ldlayer 0, layer_5583 +ldlayer 1, layer_4829 +end + +.layer layer_5583 +instr FONT01_INSTR_GUAY_HURT +legato +portamento 0x85, 34, 255 +notedv PITCH_C4, 0xA, 100 +notedv PITCH_A3, 0x1E, 100 +end + +.channel enemy_guay_die +ldlayer 0, layer_5598 +ldlayer 1, layer_4829 +end + +.layer layer_5598 +instr FONT01_INSTR_GUAY_HURT +legato +portamento 0x85, 39, 255 +notedv PITCH_G3, 0xF, 100 +notedv PITCH_DF2, 0x60, 100 +end + +.channel enemy_guay_chirp +ldlayer 0, layer_55AE +vibfreq 112 +vibdepth 64 +end + +.layer layer_55AE +instr FONT01_INSTR_ANIMALS +transpose 48 +notedv PITCH_C4, 0xC, 100 +notedv PITCH_D4, 0x14, 100 +end + +.channel enemy_guay_attack +ldlayer 0, layer_55C1 +vibfreq 112 +vibdepth 64 +end + +.layer layer_55C1 +instr FONT01_INSTR_ANIMALS +transpose 48 +notedv PITCH_F4, 0xC, 100 +notedv PITCH_D4, 0x12, 100 +notedv PITCH_E4, 0xC, 100 +notedv PITCH_D4, 0x10, 100 +end + +.channel enemy_guay_fly +instr FONT01_INSTR_OWL_FLAP +ldlayer 0, layer_55D8 +end + +.layer layer_55D8 +portamento 0x81, 22, 200 +notedv PITCH_D3, 0x26, 68 +end + +.channel enemy_biggoron_blind +ldlayer 0, layer_55E4 +end + +.layer layer_55E4 +instr FONT01_INSTR_GORON +transpose 48 +notedv PITCH_BF3, 0x45, 100 +end + +.channel enemy_biggoron_happy +ldlayer 0, layer_55F3 +ldlayer 1, layer_55F5 +end + +.layer layer_55F3 +ldelay 0xC + +.layer layer_55F5 +instr FONT01_INSTR_GORON_YAWN +transpose 48 +notedv PITCH_C4, 0x7F, 100 +end + +.channel enemy_boss_ganon_growl +ldlayer 0, layer_5604 +ldlayer 1, layer_5606 +end + +.layer layer_5604 +ldelay 0x14 + +.layer layer_5606 +instr FONT01_INSTR_MONSTER_ROAR +legato +portamento 0x85, 19, 191 +notedv PITCH_GF2, 0x34, 100 +notedv PITCH_E2, 0xC0, 100 +end + +.channel enemy_gold_skull_spin +ldlayer 0, layer_561C +ldlayer 1, layer_5626 +end + +.layer layer_561C +instr FONT01_INSTR_GRASS_RUSTLE +portamento 0x81, 31, 100 +notedv PITCH_C3, 0x32, 80 +end + +.layer layer_5626 +instr FONT01_INSTR_SLIDE_BOOTS +ldelay 0x10 +transpose 24 +notedv PITCH_C2, 0x6, 36 +notedv PITCH_F2, 0x6, 36 +notedv PITCH_C3, 0x6, 36 +notedv PITCH_F3, 0x6, 36 +notedv PITCH_C4, 0x6, 36 +end + +.channel enemy_boss_ganon_sword_clank +ldlayer 0, layer_5643 +ldlayer 1, layer_5647 +end + +.layer layer_5643 +transpose 44 +rjump layer_5649 + +.layer layer_5647 +transpose 48 +.layer layer_5649 +instr FONT01_INSTR_WITCH_ARGUE +notedv PITCH_EF4, 0x7F, 100 +end + +.channel enemy_skulltula_creak +instr FONT01_INSTR_MECH +ldlayer 0, layer_5655 +end + +.layer layer_5655 +notedv PITCH_EF3, 0x40, 100 +end + +.channel enemy_boss_twinrova_bicker +instr FONT01_INSTR_WITCH_ARGUE +ldlayer 0, layer_5675 +.channel chan_565E +rand 32 +stseq 40, layer_5675+1 +stseq 40, chan_566E+1 +rand 6 +stseq 100, layer_5675 +.channel chan_566E +ldi 1 +call delay_varyingvol +rjump chan_565E + +.layer layer_5675 +notedv PITCH_C3, 0x50, 100 +rjump layer_5675 + +.channel enemy_big_poe_caught_soul +instr FONT01_INSTR_DINO_ROAR +ldlayer 0, layer_5684 +vibfreq 56 +vibdepth 64 +end + +.layer layer_5684 +env envelope_6A2C, 230 +.layer layer_5688 +notedv PITCH_DF2, 0xD0, 56 +rjump layer_5688 + +.channel enemy_goron_child_cry +ldlayer 0, layer_5696 +vibfreq 54 +vibdepth 128 +end + +.layer layer_5696 +instr FONT01_INSTR_GORON +transpose 48 +portamento 0x81, 46, 255 +notedv PITCH_GF3, 0x70, 88 +end + +.channel enemy_spike_trap_rock +ldlayer 0, layer_56AA +vibfreq 224 +vibdepth 96 +end + +.layer layer_56AA +instr FONT01_INSTR_SLIDE_BOOTS +notedv PITCH_A2, 0x40, 76 +end + +.channel enemy_unused +end + +.filter filter_enemy0 +filter 0, 0, 0, 0, 0, 0, 0, 0 + +.filter filter_enemy1 +filter 0, 0, 0, 0, 0, 0, 0, 0 + +.filter filter_enemy2 +filter 0, 0, 0, 0, 0, 0, 0, 0 diff --git a/assets/sequences/sfxbanks/env.seq.inc b/assets/sequences/sfxbanks/env.seq.inc new file mode 100644 index 00000000000..e750f1d60d8 --- /dev/null +++ b/assets/sequences/sfxbanks/env.seq.inc @@ -0,0 +1,4070 @@ +.table table_env +entry env_door_open +entry env_door_close +entry env_explosion +entry env_horse_trot +entry env_horse_gallop +entry env_horse_neigh +entry env_river +entry env_waterfall_large +entry env_zora_surface +entry env_zora_dive +entry env_block_push +entry env_lava_bubbling_old +entry env_drawbridge_lower +entry env_drawbridge_raise +entry env_drawbridge_lowered +entry env_drawbridge_raised +entry env_bwall_break +entry env_cucco_cluck +entry env_cucco_attack +entry env_cucco_crow +entry env_door_slide_open +entry env_switch_press +entry env_horse_snort +entry env_bomb_hit_water +entry env_horse_jump +entry env_horse_land +entry env_horse_slip +entry env_fairy_awake +entry env_door_slide_close +entry env_door_stone_close +entry env_door_time_open +entry env_treasure_unlock +entry env_treasure_open +entry env_timer_tick +entry env_torch_light +entry env_guard_attention +entry env_elevator_move +entry env_warp_circle +entry env_warp_circle_enter +entry env_stairs_lower +entry env_waterfall_small +entry env_river_slow +entry env_river_fast +entry env_horse_phantom_gallop +entry env_horse_stop_sand +entry env_electric_charge +entry env_thunder_bolt_crash +entry env_bomb_rebound +entry env_water_drip +entry env_fire_crackle +entry env_lava_bubbling +entry env_flame_jet +entry env_flame_wall +entry env_block_lock +entry env_door_metal_open_unused +entry env_door_slide_unlock_unused +entry env_block_shake +entry env_crate_break +entry env_switch_hammer +entry env_lava_bubbling_eerie +entry env_fence_raise +entry env_horse_ganon_neigh +entry env_horse_ganon_snort +entry env_phantom_warp +entry env_witch_warp +entry env_water_fountain +entry env_horse_child_trot +entry env_horse_child_gallop +entry env_horse_child_neigh +entry env_horse_child_snort +entry env_barrier_node_fadeout +entry env_barrier_dispell +entry env_tree_cut +entry env_volcano_erupt +entry env_guillotine_rise +entry env_guillotine_fall +entry env_scythe_spin +entry env_guillotine_chain +entry env_plant_break +entry env_ship_bell +entry env_flag_flutter +entry env_unused +entry env_rock_break +entry env_phantom_warp2 +entry env_phantom_warp_loop +entry env_coffin_open +entry env_coffin_close +entry env_fan_spin +entry env_trap_wall_slide +entry env_door_slide_lock +entry env_door_slide_unlock +entry env_flame_jet_low +entry env_ganon_block_sink +entry env_crowd_chatter +entry env_water_change +entry env_fairy_hide +entry env_ladder_land +entry env_web_bend +entry env_web_break +entry env_unused2 +entry env_door_jabu_open +entry env_door_jabu_close +entry env_door_wood_creak_unused +entry env_gate_open +entry env_bottle_scoop_water +entry env_fish_flop +entry env_scarecrow_sway +entry env_scarecrow_spin +entry env_bottle_open +entry env_jabu_inhale +entry env_stone_resonate +entry env_triforce_flash +entry env_ruto_trip +entry env_fairy_fly +entry env_fairy_crash +entry env_spear_ready +entry env_unused3 +entry env_water_drip_unused +entry env_windmill_gear +entry env_bush_sway +entry env_horse_demo_gallop +entry env_elevator_geared_move +entry env_elevator_geared_stop +entry env_treasure_warp +entry env_door_unlock +entry env_trap_blade_move +entry env_fairy_heal_old +entry env_great_fairy_appear +entry env_great_fairy_vanish +entry env_trap_eye_fire +entry env_gears_unused +entry env_wall_move_unused +entry env_treasure_flash +entry env_windmill_blade +entry env_warp_unused +entry env_pot_break +entry env_pot_drop +entry player_large_splash +entry player_small_splash +entry env_goddess_fly +entry env_triforce_aura +entry env_triforce_glow +entry env_deku_tree_death +entry env_jabu_platform_rise +entry env_jabu_platform_fall +entry env_door_jabu_unlock +entry env_door_jabu_lock +entry env_door_time_stop +entry env_stone_restore +entry env_medal_acquire +entry env_unused4 +entry env_light_arrow_acquire +entry env_earthquake +entry env_trap_crystal +entry env_sage_warp +entry env_sage_charge +entry env_sage_charge +entry env_time_travel_end +entry env_jabu_platform_rise_stop +entry env_jabu_platform_fall_stop +entry env_goron_fall +entry env_spell_fire_stance +entry env_ice_melt +entry env_fire_pillar +entry env_unused5 +entry env_magic_vanish +entry env_ocarina_warp +entry env_ocarina_arrive +entry env_fairy_heal +entry env_door_boss_unlock +entry env_crate_small_break +entry env_crate_small_drop +entry env_ruto_rebound_jabu +entry env_door_creak_rumble +entry env_night_howl +entry env_jabu_groan +entry item_sword_swing +entry env_frog_jump +entry env_ice_freeze_old +entry env_fire_wall +entry env_wood_rebound +entry env_water_drip_unused2 +entry env_jabu_breathe +entry env_dalm_block_hit +entry env_boulder_roll +entry env_elevator_groan_unused +entry env_diamond_switch_on +entry env_kakariko_fire +entry env_rainbow_bridge_appear +entry env_flying_old +entry env_flying_end_old +entry env_deku_sprout_grow +entry env_desert_storm +entry env_triforce_mark +entry env_grave_explode +entry player_swim +entry player_lift_pot +entry env_obj_drop_water +entry env_obj_lift_water +entry env_ganondorf_cloak +entry env_dig +entry env_unused6 +entry env_lab_bubbles +entry env_ice_break_old +entry env_frog_grow +entry env_water_flow +entry env_gate_large_open +entry env_goddess_face_break +entry env_goddess_face_explode +entry env_goddess_face_crumble +entry env_trap_blade_move_old +entry system_minigame_bell +entry env_unused7 +entry env_warp_lower +entry env_sage_chamber_ambient +entry env_sage_chamber_energy +entry env_dog_bark +entry env_zelda_cast_spell +entry env_rain +entry env_door_metal_open +entry env_door_metal_close +entry env_whirlpool +entry env_tower_break +entry env_cow_moo +entry env_obj_break_unused +entry env_rock_barrier_hit +entry env_deku_sprout_grow +entry env_frog_croak_leave +entry env_frog_croak_grow +entry env_cow_moo_distant +entry env_door_ranch_close +entry env_butterfly_transform +entry system_silver_rupee +entry env_gossip_stretch +entry env_gossip_launch +entry env_door_slide_close +entry env_spike_log_roll +entry env_barrier_energy +entry env_barrier_hum +entry env_child_walk +entry env_guard_walk +entry env_pillar_stop +entry env_deku_sprout_grow +entry env_frog_croak_leave +entry env_frog_croak_grow +entry env_cow_moo_distant +entry env_door_ranch_close +entry env_butterfly_transform + +.channel env_door_open_oca +rvrbidx 1 +ldi 0 +stio 1 + +.channel env_door_open +ldlayer 0, layer_18CE +end + +.layer layer_18CE +instr FONT00_INSTR_DOOR_WOOD +notedv PITCH_A3, 0x30, 100 +instr FONT00_INSTR_CREAK +notedv PITCH_A3, 0x30, 75 +end + +.channel env_door_close +ldlayer 0, layer_18DD +end + +.layer layer_18DD +instr FONT00_INSTR_DOOR_WOOD +transpose 48 +notedv PITCH_A3, 0x60, 100 +end + +.channel env_explosion +ldlayer 0, layer_18E9 +end + +.layer layer_18E9 +instr FONT00_INSTR_EXPLOSION_0 +env envelope_65E8, 251 +notedv PITCH_A4, 0xC, 110 +notedv PITCH_A3, 0x7F, 110 +end + +.channel env_horse_trot +instr FONT00_INSTR_HORSE_GALLOP +ldlayer 0, layer_18FC +end + +.layer layer_18FC +notedv PITCH_G3, 0x18, 110 +end + +.channel env_horse_gallop +instr FONT00_INSTR_HORSE_GALLOP +ldlayer 0, layer_1906 +end + +.layer layer_1906 +notedv PITCH_C4, 0x25, 110 +end + +.channel env_horse_neigh +instr FONT00_INSTR_HORSE_VOCALS +ldlayer 0, layer_1910 +end + +.layer layer_1910 +notedv PITCH_C4, 0xAF, 110 +end + +.channel env_river +instr FONT00_INSTR_WATER_FLOWING +panweight 48 +ldlayer 0, layer_1922 +ldlayer 1, layer_1920 +end + +.layer layer_1920 +transpose 7 + +.layer layer_1922 +legato +.layer layer_1923 +notedv PITCH_C3, 0x7D00, 75 +rjump layer_1923 + +.channel env_waterfall_large +panweight 48 +ldlayer 0, layer_1936 +ldlayer 1, layer_1932 +end + +.layer layer_1932 +transpose 54 +rjump layer_1938 + +.layer layer_1936 +transpose 48 +.layer layer_1938 +instr FONT00_INSTR_WATER_FLOWING +env envelope_66F4, 220 +legato +.layer layer_193F +notedv PITCH_C4, 0x7D00, 92 +rjump layer_193F + +.channel env_zora_surface +instr FONT00_INSTR_WATER_SPLASH +env envelope_6610 +ldlayer 0, layer_194E +end + +.layer layer_194E +notedv PITCH_B4, 0x6, 100 +portamento 0x81, 48, 200 +notedv PITCH_E4, 0x48, 90 +end + +.channel env_zora_dive +ldlayer 0, layer_195D +end + +.layer layer_195D +instr FONT00_INSTR_WATER_SPLASH +env envelope_65FC, 127 +portamento 0x81, 36, 200 +notedv PITCH_A2, 0x7F, 90 +end + +.channel env_block_push +ldlayer 0, layer_196F +end + +.layer layer_196F +instr FONT00_INSTR_ROLL_BOULDER +releaserate 245 +legato +portamento 0x1, 15, 48 +.layer layer_1978 +notedv PITCH_C3, 32700, 100 +rjump layer_1978 + +.channel env_lava_bubbling_old +instr FONT00_INSTR_LAVA +panweight 48 +releaserate 112 +ldlayer 0, layer_1988 +end + +.layer layer_1988 +legato +.layer layer_1989 +notedv PITCH_E3, 32700, 100 +rjump layer_1989 + +.channel env_drawbridge_lower +ldlayer 0, layer_1996 +ldlayer 1, layer_19B0 +end + +.layer layer_1996 +instr FONT00_INSTR_CHAIN +releaserate 235 +notedvg PITCH_F3, 0x19, 56, 10 +notedvg PITCH_G3, 0x17, 56, 10 +notedvg PITCH_A3, 0x15, 56, 10 +notedvg PITCH_BF3, 0x13, 56, 10 +.layer layer_19AA +notedvg PITCH_C4, 0x13, 56, 10 +rjump layer_19AA + +.layer layer_19B0 +instr FONT00_INSTR_CHAIN_RETRACT +legato +portamento 0x85, 18, 255 +notedv PITCH_BF2, 0x14, 90 +notedv PITCH_EF3, 0xA, 90 +.layer layer_19BD +notedv PITCH_EF3, 32700, 90 +rjump layer_19BD + +.channel env_drawbridge_raise +instr FONT00_INSTR_CHAIN_RETRACT +ldlayer 0, layer_19CC +ldlayer 1, layer_19DD +end + +.layer layer_19CC +legato +portamento 0x85, 20, 255 +notedv PITCH_A2, 0x1E, 90 +notedv PITCH_E3, 0xF, 90 +.layer layer_19D7 +notedv PITCH_E3, 32700, 90 +rjump layer_19D7 + +.layer layer_19DD +instr FONT00_INSTR_CHAIN +releaserate 235 +notedvg PITCH_G3, 0x19, 56, 10 +notedvg PITCH_A3, 0x17, 56, 10 +notedvg PITCH_B3, 0x15, 56, 10 +notedvg PITCH_C4, 0x13, 56, 10 +.layer layer_19F1 +notedvg PITCH_D4, 0x11, 56, 10 +rjump layer_19F1 + +.channel env_drawbridge_lowered +env envelope_65E8 +ldlayer 0, layer_1A07 +ldlayer 1, layer_1A01 +end + +.layer layer_1A01 +instr FONT00_INSTR_SLAM_HEAVY +notedv PITCH_B2, 0x64, 75 +end + +.layer layer_1A07 +instr FONT00_INSTR_STONE_STRIKE +notedv PITCH_D1, 0xB4, 110 +end + +.channel env_drawbridge_raised +env envelope_65E8 +ldlayer 0, layer_1A1E +ldlayer 1, layer_1A18 +end + +.layer layer_1A18 +instr FONT00_INSTR_SLAM_HEAVY +notedv PITCH_B2, 0x64, 75 +end + +.layer layer_1A1E +instr FONT00_INSTR_STONE_STRIKE +notedv PITCH_AF1, 0xB4, 110 +end + +.channel env_bwall_break +ldlayer 0, layer_1A36 +ldlayer 1, layer_1B41 +end +.channel chan_1A2C +ldlayer 1, layer_1A34 +end + +.layer layer_1A30 +transpose -12 +rjump layer_1A36 + +.layer layer_1A34 +transpose -24 + +.layer layer_1A36 +instr FONT00_INSTR_EXPLOSION_0 +env envelope_6688, 230 +portamento 0x81, 58, 127 +notedv PITCH_C4, 0x52, 95 +portamento 0x81, 51, 127 +notedv PITCH_F3, 0xB9, 70 +end + +.channel env_cucco_cluck +instr FONT00_INSTR_ANIMALS_0 +ldlayer 0, layer_1A52 +end + +.layer layer_1A52 +portamento 0x81, 39, 255 +notedv PITCH_DF4, 0xA0, 105 +end + +.channel env_cucco_attack +ldlayer 0, layer_1A5F +end + +.layer layer_1A5F +instr FONT00_INSTR_ANIMALS_1 +notedvg PITCH_AF3, 0xC, 95, 10 +instr FONT00_INSTR_ANIMALS_0 +env envelope_65D8, 251 +portamento 0x81, 51, 127 +notedv PITCH_E4, 0x48, 105 +end + +.channel env_cucco_crow +instr FONT00_INSTR_ANIMALS_1 +ldlayer 0, layer_1A79 +end + +.layer layer_1A79 +notedv PITCH_C4, 0xA6, 105 +end + +.channel env_door_slide_open +instr FONT00_INSTR_DOOR_METAL +env envelope_6610 +ldlayer 0, layer_1A87 +end + +.layer layer_1A87 +portamento 0x81, 32, 175 +notedv PITCH_B3, 0x30, 115 +end + +.channel env_switch_press +ldlayer 0, layer_1A96 +ldlayer 1, layer_1AA5 +end + +.layer layer_1A96 +instr FONT00_INSTR_STICK_ATTACK +notedv PITCH_C4, 0x4, 105 +instr FONT00_INSTR_STONE_STRIKE +env envelope_664C, 255 +notedv PITCH_BF1, 0x28, 105 +end + +.layer layer_1AA5 +instr FONT00_INSTR_STONE_STRIKE +env envelope_664C, 251 +notedvg PITCH_C3, 0x4, 102, 96 +notedv PITCH_BF1, 0x28, 102 +end + +.channel env_horse_snort +ldlayer 0, layer_1AB7 +end + +.layer layer_1AB7 +transpose 48 +.layer layer_1AB9 +instr FONT00_INSTR_HORSE_VOCALS +legato +portamento 0x85, 34, 255 +notedv PITCH_AF3, 0x6, 85 +notedv PITCH_EF3, 0x8, 85 +notedv PITCH_B2, 0x73, 85 +end + +.channel env_bomb_hit_water +ldlayer 0, layer_1AD0 +end + +.layer layer_1ACE +transpose 6 + +.layer layer_1AD0 +instr FONT00_INSTR_WATER_SPLISH +notedv PITCH_F4, 0x5C, 115 +end + +.channel env_horse_jump +instr FONT00_INSTR_HORSE_GALLOP +ldlayer 0, layer_1ADC +end + +.layer layer_1ADC +notedv PITCH_D4, 0x8, 110 +notedv PITCH_E4, 0xF, 110 +end + +.channel env_horse_land +instr FONT00_INSTR_HORSE_GALLOP +ldlayer 0, layer_1AE9 +end + +.layer layer_1AE9 +notedv PITCH_F4, 0xA, 110 +notedv PITCH_D4, 0x12, 110 +end + +.channel env_horse_slip +instr FONT00_INSTR_SLIDE_BLOCK +env envelope_667C +ldlayer 0, layer_1AF9 +end + +.layer layer_1AF9 +portamento 0x81, 38, 255 +notedv PITCH_C3, 0x3C, 80 +end + +.channel env_fairy_awake +ldlayer 0, layer_1B05 +end + +.layer layer_1B05 +instr FONT00_INSTR_FAIRY_MAGIC +env envelope_6794, 251 +portamento 0x1, 52, 256 +notedv PITCH_B5, 0x48, 65 +end + +.channel env_door_slide_close +instr FONT00_INSTR_DOOR_METAL +env envelope_6610 +ldlayer 0, layer_1B1D +end + +.layer layer_1B1D +portamento 0x81, 38, 175 +notedv PITCH_F3, 0x30, 115 +end + +.channel env_door_stone_close +gain 20 +ldlayer 0, layer_1B2E +ldlayer 1, layer_1B41 +end + +.layer layer_1B2E +instr FONT00_INSTR_MECH_CHARGE +releaserate 160 +notedv PITCH_E4, 0x32, 102 +.layer layer_1B35 +instr FONT00_INSTR_BLOCK_LOCK +env envelope_6740, 245 +notedv PITCH_E2, 0x64, 80 +end + +.layer layer_1B3F +transpose 4 + +.layer layer_1B41 +instr FONT00_INSTR_BLOCK_LOCK +notedv PITCH_E3, 0x64, 110 +end + +.channel env_door_time_open +instr FONT00_INSTR_DOOR_METAL +env envelope_6674 +ldlayer 0, layer_1B57 +ldlayer 1, layer_1B53 +end + +.layer layer_1B53 +instr FONT00_INSTR_MECH_CHARGE +transpose 22 + +.layer layer_1B57 +legato +portamento 0x81, 34, 175 +.layer layer_1B5C +notedv PITCH_A2, 0x60, 115 +rjump layer_1B5C + +.channel env_treasure_unlock +ldlayer 0, layer_1B71 +ldlayer 1, layer_1B68 +end + +.layer layer_1B68 +instr FONT00_INSTR_DOOR_WOOD +notedv PITCH_A4, 0x3, 115 +notedv PITCH_E5, 0x6, 115 +end + +.layer layer_1B71 +ldelay 0x19 +instr FONT00_INSTR_CREAK +portamento 0x81, 31, 255 +notedv PITCH_G3, 0x18, 100 +end + +.channel env_treasure_open +ldlayer 0, layer_1B81 +end + +.layer layer_1B81 +instr FONT00_INSTR_CREAK +env envelope_65FC, 250 +portamento 0x83, 32, 255 +notedvg PITCH_D3, 0x18, 100, 127 +notedv PITCH_C4, 0x48, 100 +end + +.channel env_timer_tick +instr FONT00_INSTR_BOW +ldi 7 +call delay_varyingvol +notealloc 2 +allocnotelist 2 +ldlayer 0, layer_1BBA +.channel chan_1BA1 +ldio 6 +and 3 +ldseq addr_1BB6 +stseq 0, layer_fn_1BE6+1 +stseq 8, @+1 +ldi 48 +call delay_varyingvol +rjump chan_1BA1 + +.array addr_1BB6 +byte 0x20 +byte 0xE +byte 0x5 +byte 0x20 + +.layer layer_1BBA +transpose 48 +.layer layer_1BBC +notedvg PITCH_B3, 0x2, 70, 127 +notedv PITCH_C3, 0x2, 70 +call layer_fn_1BE6 +notedvg PITCH_F3, 0x2, 70, 127 +notedv PITCH_GF2, 0x2, 70 +call layer_fn_1BE6 +notedvg PITCH_B4, 0x2, 70, 127 +notedv PITCH_C4, 0x2, 70 +call layer_fn_1BE6 +notedvg PITCH_F4, 0x2, 70, 127 +notedv PITCH_GF3, 0x2, 70 +call layer_fn_1BE6 +rjump layer_1BBC + +.layer layer_fn_1BE6 +ldelay 0x14 +end + +.channel env_torch_light +gain 15 +ldlayer 0, layer_1BEF +end + +.layer layer_1BEF +instr FONT00_INSTR_IGNITE +portamento 0x81, 27, 152 +notedv PITCH_C4, 0x3C, 100 +end + +.channel env_guard_attention +instr FONT00_INSTR_SWORD_STRIKE +ldlayer 0, layer_1C05 +ldlayer 1, layer_1C0B +ldlayer 2, layer_1C0F +end + +.layer layer_1C05 +ldelay 0x2 +notedv PITCH_C4, 0x1E, 90 +end + +.layer layer_1C0B +notedv PITCH_E4, 0x1E, 90 +end + +.layer layer_1C0F +transpose -12 +jump layer_12E7 + +.channel env_elevator_move +ldlayer 0, layer_1C1D +ldlayer 1, layer_1C1B +end + +.layer layer_1C1B +transpose -12 + +.layer layer_1C1D +instr FONT00_INSTR_DOOR_METAL +env envelope_6674, 251 +legato +portamento 0x1, 26, 60 +.layer layer_1C28 +notedv PITCH_A3, 32700, 95 +rjump layer_1C28 + +.channel env_warp_circle +instr FONT00_INSTR_WARP +releaserate 182 +ldlayer 0, layer_1C65 +ldlayer 1, layer_1C6F +ldlayer 2, layer_1C61 +.channel chan_1C3B +ldio 3 +and 240 +rbeqz chan_1C4E +ldptr 0x0 +stptrtoseq envelope_1C7E+2 +ldptr 32700 +stptrtoseq envelope_1C8A+2 +rjump chan_1C5A +.channel chan_1C4E +ldptr 0x0 +stptrtoseq envelope_1C8A+2 +ldptr 32700 +stptrtoseq envelope_1C7E+2 +.channel chan_1C5A +ldi 1 +call delay +rjump chan_1C3B + +.layer layer_1C61 +stereo 20 +rjump layer_1C65 + +.layer layer_1C65 +legato +notedv PITCH_AF4, 0xC, 75 +.layer layer_1C69 +notedv PITCH_BF4, 32700, 75 +rjump layer_1C69 + +.layer layer_1C6F +legato +notedv PITCH_D5, 0xC, 75 +.layer layer_1C73 +notedv PITCH_D5, 32700, 75 +rjump layer_1C73 + +.envelope envelope_unused_1C7A +point 1, 32700 +.envelope envelope_1C7E +point 80, 32700 +goto 1 + +.envelope envelope_unused_1C86 +point 1, 0 +.envelope envelope_1C8A +point 80, 32700 +goto 1 + +.envelope envelope_unused_1C92 +point 1, 32700 +point 80, 32700 +goto 1 + +.channel env_warp_circle_enter +instr FONT00_INSTR_WARP +panweight 48 +ldi 25 +stio 1 +env envelope_6750 +releaserate 232 +ldlayer 0, layer_1CB4 +ldlayer 1, layer_1CCB +ldlayer 2, layer_1CE7 +end + +.layer layer_1CB4 +notepan 24 +transpose 12 +notedv PITCH_D4, 0x18, 75 +legato +releaserate 251 +portamento 0x85, 53, 255 +notedv PITCH_D5, 0x190, 90 +notedv PITCH_E5, 500, 90 +end + +.layer layer_1CCB +notepan 64 +transpose 12 +notedv PITCH_D4, 0x18, 75 +notedv PITCH_D5, 0x190, 75 +transpose 0 +instr FONT00_INSTR_FAIRY +env envelope_6778, 251 +portamento 0x81, 57, 255 +notedv PITCH_BF5, 500, 50 +end + +.layer layer_1CE7 +notepan 104 +transpose 24 +notedv PITCH_BF3, 0x18, 75 +legato +releaserate 251 +portamento 0x85, 49, 255 +notedv PITCH_BF4, 0x190, 90 +notedv PITCH_C5, 500, 90 +end + +.channel env_stairs_lower +instr FONT00_INSTR_EXPLOSION_0 +panweight 72 +ldlayer 0, layer_1D0C +ldlayer 1, layer_1D70 +ldlayer 2, layer_1D44 +end + +.layer layer_1D0C +env envelope_65E8, 200 +transpose -8 +.layer layer_1D12 +notepan 34 +notedv PITCH_A4, 0x8, 100 +notedv PITCH_A3, 0x18, 100 +notepan 74 +notedv PITCH_B4, 0x6, 85 +notedv PITCH_B3, 0x15, 85 +notepan 54 +notedv PITCH_F4, 0x9, 91 +notedv PITCH_G3, 0x1A, 91 +notepan 94 +notedv PITCH_A4, 0x7, 102 +notedv PITCH_F3, 0xB, 102 +notepan 44 +notedv PITCH_G4, 0x9, 86 +notedv PITCH_F3, 0x1D, 86 +notepan 64 +notedv PITCH_G4, 0x5, 88 +notedv PITCH_A3, 0x1B, 88 +rjump layer_1D12 + +.layer layer_1D44 +env envelope_65E8, 127 +transpose -8 +.layer layer_1D4A +notedv PITCH_G3, 0x9, 73 +notedv PITCH_F2, 0x22, 73 +notedv PITCH_A3, 0x9, 79 +notedv PITCH_F2, 0x1D, 79 +notedv PITCH_A3, 0x9, 87 +notedv PITCH_F2, 0x1B, 87 +notedv PITCH_E3, 0x7, 81 +notedv PITCH_D2, 0xF, 81 +notedv PITCH_A3, 0x9, 68 +notedv PITCH_C2, 0x18, 68 +notedv PITCH_G3, 0x5, 70 +notedv PITCH_C2, 0x21, 70 +rjump layer_1D4A + +.layer layer_1D70 +instr FONT00_INSTR_DOOR_METAL +.layer layer_1D72 +notedv PITCH_DF3, 0x1C, 102 +rjump layer_1D72 + +.channel env_waterfall_small +instr FONT00_INSTR_WATER_FLOWING +panweight 48 +releaserate 211 +ldlayer 0, layer_1D86 +ldlayer 1, layer_1D84 +end + +.layer layer_1D84 +transpose 10 + +.layer layer_1D86 +legato +.layer layer_1D87 +notedv PITCH_A3, 0x7D00, 75 +rjump layer_1D87 + +.channel env_river_slow +instr FONT00_INSTR_WATER_FLOWING +panweight 64 +ldlayer 0, layer_1D9A +ldlayer 1, layer_1D98 +end + +.layer layer_1D98 +transpose 4 + +.layer layer_1D9A +legato +.layer layer_1D9B +notedv PITCH_G2, 0x7D00, 60 +rjump layer_1D9B + +.channel env_river_fast +instr FONT00_INSTR_WATER_FLOWING +panweight 64 +ldlayer 0, layer_1DAE +ldlayer 1, layer_1DAC +end + +.layer layer_1DAC +transpose 7 + +.layer layer_1DAE +legato +.layer layer_1DAF +notedv PITCH_G3, 0x7D00, 75 +rjump layer_1DAF + +.channel env_horse_phantom_gallop +instr FONT00_INSTR_HORSE_GALLOP +ldlayer 0, layer_1DBB +end + +.layer layer_1DBB +notedv PITCH_B3, 0x12, 110 +end + +.channel env_horse_stop_sand +instr FONT00_INSTR_SLIDE_BLOCK +env envelope_667C +ldlayer 0, layer_1DC8 +end + +.layer layer_1DC8 +portamento 0x81, 38, 255 +notedv PITCH_C4, 0x20, 80 +end + +.channel env_electric_charge +instr FONT00_INSTR_POTTERY_ELECTRIC +ldi 32 +stio 1 +releaserate 245 +ldlayer 0, layer_1DE6 +ldlayer 1, layer_1DDE +end + +.layer layer_1DDE +portamento 0x81, 22, 255 +notedv PITCH_G3, 0x78, 70 +end + +.layer layer_1DE6 +portamento 1, 34, 48 +notedv PITCH_G4, 0x78, 70 +end + +.channel env_thunder_bolt_crash +gain 15 +ldlayer 0, layer_1DFE +ldlayer 1, layer_1DFA +ldlayer 2, layer_1E0A +end + +.layer layer_1DFA +instr FONT00_INSTR_EXPLOSION_0 +rjump layer_1E02 + +.layer layer_1DFE +transpose 42 +instr FONT00_INSTR_FLAME_THUNDER +.layer layer_1E02 +env envelope_65FC, 200 +notedv PITCH_DF4, 0x0, 110 +end + +.layer layer_1E0A +instr FONT00_INSTR_POTTERY_ELECTRIC +notedv PITCH_G3, 0x32, 50 +end + +.channel env_bomb_rebound +ldlayer 0, layer_1E14 +end + +.layer layer_1E14 +instr FONT00_INSTR_SLAM_HEAVY +env envelope_6660, 251 +legato +portamento 0x85, 48, 255 +notedv PITCH_C3, 0x4, 95 +notedv PITCH_BF3, 0x5, 95 +end + +.channel env_water_drip +instr FONT00_INSTR_WATER_DRIP +env envelope_6624 +releaserate 201 +ldi 20 +stio 1 +panweight 0 +ldlayer 0, layer_1E3C +ldlayer 1, layer_1E57 +ldlayer 2, layer_1E74 +end + +.layer layer_1E3C +notepan 74 +call layer_fn_1E7F +notepan 84 +call layer_fn_1E88 +notepan 89 +call layer_fn_1E91 +notepan 69 +call layer_fn_1E96 +notepan 78 +call layer_fn_1E9F +rjump layer_1E3C + +.layer layer_1E57 +ldelay 0x44 +notepan 34 +call layer_fn_1E9F +notepan 44 +call layer_fn_1E96 +notepan 54 +call layer_fn_1E91 +notepan 47 +call layer_fn_1E88 +notepan 41 +call layer_fn_1E7F +rjump layer_1E57 + +.layer layer_1E74 +call layer_fn_1EA8 +lldelay 0x64 +call layer_fn_1E7F +rjump layer_1E57 + +.layer layer_fn_1E7F +notedv PITCH_C4, 0x172, 98 +notedv PITCH_AF3, 0x10C, 56 +end + +.layer layer_fn_1E88 +notedv PITCH_A3, 0x113, 65 +notedv PITCH_BF3, 0x140, 92 +end + +.layer layer_fn_1E91 +notedv PITCH_B3, 0x159, 76 +end + +.layer layer_fn_1E96 +notedv PITCH_G3, 0xD7, 98 +notedv PITCH_D4, 0x1CC, 106 +end + +.layer layer_fn_1E9F +notedv PITCH_A3, 0x120, 92 +notedv PITCH_BF3, 0x13B, 88 +end + +.layer layer_fn_1EA8 +stereo 20 +end + +.channel env_fire_crackle +instr FONT00_INSTR_FIRE_COW +gain 10 +ldlayer 0, layer_1EB3 +end + +.layer layer_1EB3 +legato +.layer layer_1EB4 +notedv PITCH_BF3, 32700, 100 +rjump layer_1EB4 + +.channel env_lava_bubbling +panweight 48 +ldlayer 0, layer_1EC3 +ldlayer 1, layer_1ED4 +end + +.layer layer_1EC3 +instr FONT00_INSTR_LAVA +legato +portamento 0x85, 32, 200 +.layer layer_1ECA +notedv PITCH_A3, 500, 105 +notedv PITCH_F3, 500, 105 +rjump layer_1ECA + +.layer layer_1ED4 +instr FONT00_INSTR_EXPLOSION_0 +env envelope_667C, 221 +.layer layer_1EDA +portamento 0x81, 27, 255 +notedv PITCH_F2, 0x190, 65 +portamento 0x81, 27, 255 +notedv PITCH_F4, 0x2BC, 65 +rjump layer_1EDA + +.channel env_flame_jet +ldlayer 0, layer_1EF0 +end + +.layer layer_1EF0 +instr FONT00_INSTR_FLAME_THUNDER +releaserate 240 +legato +portamento 1, 24, 40 +.layer layer_1EF9 +notedv PITCH_F3, 32700, 100 +rjump layer_1EF9 + +.channel env_flame_wall +ldlayer 0, layer_1F03 +end + +.layer layer_1F03 +instr FONT00_INSTR_FLAME_THUNDER +env envelope_667C, 240 +legato +portamento 0x85, 32, 255 +notedv PITCH_C4, 0x60, 100 +.layer layer_1F11 +notedv PITCH_B3, 0x60, 100 +rjump layer_1F11 + +.channel env_block_lock +ldlayer 0, layer_1F1C +end + +.layer layer_1F1A +transpose -4 + +.layer layer_1F1C +instr FONT00_INSTR_BLOCK_LOCK +releaserate 241 +notedv PITCH_GF4, 0x6, 110 +notedv PITCH_EF3, 0x64, 110 +end + +.channel env_door_metal_open_unused +ldlayer 0, layer_1F2B +end + +.layer layer_1F2B +instr FONT00_INSTR_MECH_ROTATE +releaserate 240 +legato +portamento 0x85, 25, 255 +notedv PITCH_D3, 0x28, 75 +.layer layer_1F37 +notedv PITCH_E3, 0x141, 75 +rjump layer_1F37 + +.channel env_door_slide_unlock_unused +ldlayer 0, layer_1F43 +end + +.layer layer_1F41 +transpose -6 + +.layer layer_1F43 +instr FONT00_INSTR_SLAM_LIGHT +releaserate 241 +notedv PITCH_A3, 0x5E, 95 +end + +.channel env_block_shake +instr FONT00_INSTR_BLOCK_LOCK +env envelope_6660 +ldlayer 0, layer_1F57 +ldlayer 1, layer_1F5F +end + +.layer layer_1F57 +portamento 0x81, 43, 200 +notedv PITCH_C3, 0x14, 110 +end + +.layer layer_1F5F +instr FONT00_INSTR_EXPLOSION_0 +notedv PITCH_A2, 0x14, 100 +end + +.channel env_crate_break +gain 10 +ldlayer 0, layer_1F6E +ldlayer 1, layer_1F7B +end + +.layer layer_1F6E +instr FONT00_INSTR_EXPLOSION_0 +env envelope_6610, 251 +notedv PITCH_C5, 0xF, 94 +notedv PITCH_EF4, 0x60, 99 +end + +.layer layer_1F7B +instr FONT00_INSTR_STICK_ATTACK +env envelope_65E8, 180 +notedv PITCH_GF4, 0x8, 92 +notedv PITCH_EF4, 0x6, 85 +notedv PITCH_BF3, 0x5, 94 +notedv PITCH_GF3, 0xA, 89 +notedv PITCH_BF2, 0x50, 95 +end + +.channel env_switch_hammer +ldlayer 0, layer_1F98 +ldlayer 1, layer_1FA2 +end + +.layer layer_1F98 +instr FONT00_INSTR_BLOCK_LOCK +notedvg PITCH_DF5, 0x12, 95, 127 +notedv PITCH_DF4, 0x41, 95 +end + +.layer layer_1FA2 +instr FONT00_INSTR_STONE_STRIKE +notedv PITCH_C4, 0x12, 80 +notedv PITCH_C3, 0x41, 80 +end + +.channel env_lava_bubbling_eerie +panweight 48 +ldlayer 0, layer_1FB4 +ldlayer 1, layer_1FC5 +end + +.layer layer_1FB4 +instr FONT00_INSTR_LAVA +legato +portamento 0x85, 38, 200 +.layer layer_1FBB +notedv PITCH_EF4, 0x19A, 110 +notedv PITCH_B3, 0x17C, 110 +rjump layer_1FBB + +.layer layer_1FC5 +instr FONT00_INSTR_EXPLOSION_0 +env envelope_667C, 221 +.layer layer_1FCB +portamento 0x81, 32, 255 +notedv PITCH_B2, 0x136, 80 +portamento 0x81, 32, 255 +notedv PITCH_B4, 0x226, 80 +rjump layer_1FCB + +.channel env_fence_raise +ldlayer 0, layer_1FF1 +ldlayer 1, layer_1FE4 +end + +.layer layer_1FE4 +instr FONT00_INSTR_EXPLOSION_0 +env envelope_664C, 240 +notedv PITCH_F5, 0x3, 70 +notedv PITCH_F3, 0x4, 64 +end + +.layer layer_1FF1 +instr FONT00_INSTR_SWORD_STRIKE +transpose 48 +notedvg PITCH_D2, 0x3, 100, 127 +notedv PITCH_E3, 0x30, 100 +end + +.channel env_horse_ganon_neigh +instr FONT00_INSTR_HORSE_VOCALS +ldlayer 0, layer_2003 +end + +.layer layer_2003 +legato +portamento 0x85, 38, 127 +notedv PITCH_D4, 0x50, 110 +notedv PITCH_G3, 0x73, 110 +end + +.channel env_horse_ganon_snort +ldlayer 0, layer_2013 +end + +.layer layer_2013 +instr FONT00_INSTR_HORSE_VOCALS +transpose 48 +legato +portamento 0x85, 32, 255 +notedv PITCH_BF3, 0x6, 85 +notedv PITCH_EF3, 0x10, 85 +notedv PITCH_A2, 0x73, 85 +end + +.channel env_phantom_warp +ldlayer 0, layer_2065 +ldlayer 1, layer_203C +vibfreq 255 +vibdepthgrad 50, 80, 100 +ldi 255 +call delay_varyingvol +vibdepthgrad 80, 10, 100 +end + +.layer layer_203C +instr FONT00_INSTR_FLAME_THUNDER +env envelope_6694, 231 +legato +portamento 0x85, 3, 255 +notedv PITCH_F2, 0x60, 100 +notedv PITCH_C4, 0x96, 100 +nolegato +legato +noportamento +env envelope_66EC, 231 +portamento 0x81, 15, 255 +notedv PITCH_C4, 0xC8, 100 +end + +.layer layer_unused_205E +transpose -30 +instr FONT00_INSTR_OCARINA_0 +jump layer_2069 + +.layer layer_2065 +transpose 12 +instr FONT00_INSTR_WARP +.layer layer_2069 +env envelope_6688, 251 +legato +portamento 0x85, 15, 255 +notedv PITCH_F3, 0x60, 74 +notedv PITCH_C5, 0xC8, 74 +notedv PITCH_A5, 0x96, 74 +end + +.channel env_witch_warp +ldlayer 0, layer_20A3 +ldlayer 1, layer_208C +ldlayer 2, layer_209C +vibfreq 255 +vibdepth 50 +end + +.layer layer_208C +instr FONT00_INSTR_FLAME_THUNDER +env envelope_667C, 211 +legato +portamento 0x85, 3, 255 +.layer layer_2097 +notedv PITCH_F2, 0x60, 100 +rjump layer_2097 + +.layer layer_209C +transpose -18 +instr FONT00_INSTR_OCARINA_0 +jump layer_20A7 + +.layer layer_20A3 +instr FONT00_INSTR_WARP +transpose 12 +.layer layer_20A7 +env envelope_667C, 211 +legato +portamento 0x85, 15, 255 +.layer layer_20B0 +notedv PITCH_F3, 0x60, 74 +rjump layer_20B0 + +.channel env_water_fountain +ldlayer 0, layer_20BC +ldlayer 1, layer_20C7 +end + +.layer layer_20BC +instr FONT00_INSTR_WATER_FLOWING +transpose 48 +.layer layer_20C0 +legato +.layer layer_20C1 +notedv PITCH_GF4, 32700, 64 +rjump layer_20C1 + +.layer layer_20C7 +instr FONT00_INSTR_WATER_FLOWING +rjump layer_20C0 + +.channel env_horse_child_trot +instr FONT00_INSTR_HORSE_GALLOP +releaserate 245 +ldlayer 0, layer_20D3 +end + +.layer layer_20D3 +notedv PITCH_C4, 0x9, 110 +end + +.channel env_horse_child_gallop +instr FONT00_INSTR_HORSE_GALLOP +ldlayer 0, layer_20DD +end + +.layer layer_20DD +notedv PITCH_E4, 0x18, 110 +end + +.channel env_horse_child_neigh +instr FONT00_INSTR_HORSE_VOCALS +ldlayer 0, layer_20E7 +end + +.layer layer_20E7 +notedv PITCH_E4, 0x91, 110 +end + +.channel env_horse_child_snort +ldlayer 0, layer_20F0 +end + +.layer layer_20F0 +transpose 52 +jump layer_1AB9 + +.channel env_barrier_node_fadeout +gain 15 +ldlayer 0, layer_20FE +ldlayer 1, layer_210B +end + +.layer layer_20FE +instr FONT00_INSTR_FAIRY +env envelope_67F4, 221 +transpose 24 +notedv PITCH_C4, 0xF8, 75 +end + +.layer layer_210B +instr FONT00_INSTR_WARP +env envelope_67F4, 221 +transpose 36 +notedv PITCH_C4, 0xF8, 100 +end + +.channel env_barrier_dispell +instr FONT00_INSTR_WARP +ldlayer 0, layer_2130 +ldlayer 1, layer_2124 +ldlayer 2, layer_2147 +end + +.layer layer_2124 +transpose 27 +rjump layer_2132 + +.layer layer_unused_2128 +transpose 33 +env envelope_65FC, 240 +rjump layer_2132 + +.layer layer_2130 +transpose 24 +.layer layer_2132 +legato +portamento 0x81, 40, 255 +.layer layer_2137 +noteldv PITCH_D4, 0x30, 80 +rjump layer_2137 + +.layer layer_unused_213D +transpose 32 +instr FONT00_INSTR_SHIMMER +env envelope_65FC, 240 +rjump layer_214F + +.layer layer_2147 +transpose 48 +.layer layer_2149 +instr FONT00_INSTR_SHIMMER +env envelope_66FC, 240 +.layer layer_214F +legato +.layer layer_2150 +notedv PITCH_C5, 0x7D00, 50 +rjump layer_2150 + +.channel env_tree_cut +ldlayer 0, layer_215D +ldlayer 1, layer_216D +end + +.layer layer_215D +ldelay 0x6 +legato +instr FONT00_INSTR_STEP_GRASS +portamento 0x85, 32, 255 +notedv PITCH_A3, 0x18, 80 +notedv PITCH_G2, 0x32, 80 +end + +.layer layer_216D +instr FONT00_INSTR_WOOD_BREAK +notedvg PITCH_E3, 0xA, 93, 127 +notedv PITCH_GF2, 0x1F, 90 +end + +.channel env_volcano_erupt +panweight 96 +ldlayer 0, layer_2185 +ldlayer 1, layer_2190 +ldlayer 2, layer_2183 +end + +.layer layer_2183 +transpose -6 + +.layer layer_2185 +instr FONT00_INSTR_MECH_CHARGE +releaserate 221 +legato +.layer layer_218A +notedv PITCH_F4, 0x7D00, 90 +rjump layer_218A + +.layer layer_2190 +instr FONT00_INSTR_EXPLOSION_0 +env envelope_6674, 221 +.layer layer_2196 +notepan 64 +notedv PITCH_B4, 0x50, 85 +notepan 45 +notedv PITCH_G4, 0x50, 85 +notepan 97 +notedv PITCH_F4, 0x40, 85 +notepan 74 +notedv PITCH_A4, 0x31, 85 +notepan 82 +notedv PITCH_D5, 0x3A, 85 +notepan 37 +notedv PITCH_A4, 0x25, 85 +notepan 54 +notedv PITCH_F4, 0x3D, 85 +notepan 29 +notedv PITCH_C5, 0x20, 85 +rjump layer_2196 + +.channel env_guillotine_rise +ldlayer 0, layer_21C7 +ldlayer 1, layer_21CD +end + +.layer layer_21C7 +instr FONT00_INSTR_CHAIN +notedv PITCH_E4, 0x18, 80 +end + +.layer layer_21CD +instr FONT00_INSTR_SWORD_DRAW +portamento 0x81, 28, 255 +notedv PITCH_EF3, 0x18, 95 +end + +.channel env_guillotine_fall +ldlayer 0, layer_21ED +ldlayer 1, layer_21DE +end + +.layer layer_21DE +instr FONT00_INSTR_EXPLOSION_0 +portamento 0x81, 39, 255 +notedv PITCH_AF2, 0x8, 70 +instr FONT00_INSTR_SWORD_STRIKE +notedv PITCH_E3, 0x8, 90 +end + +.layer layer_21ED +instr FONT00_INSTR_CHAIN +notedv PITCH_A4, 0x6, 80 +instr FONT00_INSTR_SWORD_DRAW +portamento 0x81, 38, 255 +notedv PITCH_F3, 0xE, 95 +end + +.channel env_scythe_spin +ldlayer 0, layer_2200 +end + +.layer layer_2200 +instr FONT00_INSTR_MECH_ROTATE +releaserate 240 +.layer layer_2204 +portamento 0x81, 27, 255 +notedv PITCH_A2, 0x40, 72 +rjump layer_2204 + +.channel env_guillotine_chain +instr FONT00_INSTR_CHAIN +ldlayer 0, layer_221A +ldlayer 1, layer_2216 +end + +.layer layer_2216 +instr FONT00_INSTR_CHAIN_RETRACT +transpose -2 + +.layer layer_221A +legato +portamento 1, 40, 116 +.layer layer_221F +notedv PITCH_G4, 32700, 76 +rjump layer_221F + +.channel env_plant_break +ldlayer 0, layer_2232 +ldlayer 1, layer_222C +end + +.layer layer_222C +instr FONT00_INSTR_EXPLOSION_0 +notedv PITCH_G3, 0x14, 100 +end + +.layer layer_2232 +instr FONT00_INSTR_STEP_GRASS +notedvg PITCH_E3, 0x6, 90, 127 +notedvg PITCH_BF3, 0x6, 90, 127 +notedv PITCH_E4, 0x2A, 90 +end + +.channel env_ship_bell +instr FONT00_INSTR_FAIL_BELLS +env envelope_6624 +ldi 32 +stio 1 +ldlayer 0, layer_2253 +ldlayer 1, layer_224F +end + +.layer layer_224F +transpose 60 +rjump layer_2257 + +.layer layer_2253 +transpose 48 +ldelay 0x5 +.layer layer_2257 +notedv PITCH_A3, 0x9, 80 +notedv PITCH_GF3, 0x53, 80 +ldelay 0x64 +rjump layer_2257 + +.channel env_flag_flutter +ldi 96 +stseq 0, chan_2287+1 +.channel chan_2267 +instr FONT00_INSTR_CLOAK +env envelope_66EC +releaserate 231 +ldi 4 +stio 6 +ldlayer 0, layer_2298 +.channel chan_2274 +rand 31 +stseq 14, layer_2298+1 +stseq 14, chan_2291+1 +stseq 45, layer_2298+2 +rand 8 +subio 6 +and 7 +.channel chan_2287 +stseq 96, layer_2298 +ldio 6 +sub 252 +and 4 +stio 6 +.channel chan_2291 +ldi 1 +call delay_varyingvol +rjump chan_2274 + +.layer layer_2298 +notedv PITCH_C4, 0x47, 80 +rjump layer_2298 + +.channel env_unused +ldlayer 0, layer_1F43 +ldlayer 1, layer_1F1C +end + +.channel env_rock_break +gain 18 +ldlayer 0, layer_22AA +end + +.layer layer_22AA +instr FONT00_INSTR_EXPLOSION_0 +env envelope_6624, 246 +notedvg PITCH_EF4, 0x9, 105, 192 +env envelope_6610, 220 +notedv PITCH_B2, 0x0, 105 +end + +.channel env_phantom_warp2 +instr FONT00_INSTR_OCARINA_0 +env envelope_6674 +ldlayer 0, layer_22CB +vibdepth 255 +vibfreqgrad 4, 64, 100 +end + +.layer layer_22CB +notedv PITCH_D2, 0x1C2, 80 +end + +.channel env_phantom_warp_loop +instr FONT00_INSTR_OCARINA_0 +env envelope_6674 +ldlayer 0, layer_22DF +vibdepth 255 +vibfreqgrad 2, 7, 25 +end + +.layer layer_22DF +legato +.layer layer_22E0 +notedv PITCH_C2, 32700, 80 +rjump layer_22E0 + +.channel env_coffin_open +ldlayer 0, layer_22EA +end + +.layer layer_22EA +instr FONT00_INSTR_DOOR_WOOD +notedv PITCH_C3, 0x13, 105 +instr FONT00_INSTR_CREAK +notedv PITCH_B1, 0x49, 103 +end + +.channel env_coffin_close +instr FONT00_INSTR_STICK_ATTACK +ldlayer 0, layer_22FB +end + +.layer layer_22FB +notedv PITCH_DF2, 0x8, 100 +notedv PITCH_D3, 0x18, 100 +end + +.channel env_fan_spin +ldlayer 0, layer_230B +ldlayer 1, layer_2309 +end + +.layer layer_2309 +transpose 5 + +.layer layer_230B +legato +instr FONT00_INSTR_WIND_HOWL_S +env envelope_6674, 200 +portamento 1, 56, 127 +.layer layer_2316 +notedv PITCH_B5, 32700, 85 +rjump layer_2316 + +.channel env_trap_wall_slide +ldlayer 0, layer_2327 +ldlayer 1, layer_2325 +gain 24 +end + +.layer layer_2325 +transpose 4 + +.layer layer_2327 +instr FONT00_INSTR_CREAK +portamento 0x84, 19, 127 +.layer layer_232D +notedv PITCH_D1, 0x9, 110 +rjump layer_232D + +.channel env_door_slide_lock +instr FONT00_INSTR_MECH_ROTATE +ldlayer 0, layer_2338 +end + +.layer layer_2338 +portamento 0x81, 32, 175 +notedv PITCH_B3, 0x30, 80 +end + +.channel env_door_slide_unlock +instr FONT00_INSTR_MECH_ROTATE +ldlayer 0, layer_2346 +end + +.layer layer_2346 +portamento 0x81, 38, 175 +notedv PITCH_F3, 0x30, 80 +end + +.channel env_flame_jet_low +gain 10 +ldlayer 0, layer_2357 +ldlayer 1, layer_2366 +end + +.layer layer_2357 +instr FONT00_INSTR_FIRE_COW +releaserate 221 +legato +portamento 0x81, 52, 255 +.layer layer_2360 +notedv PITCH_F4, 0xC8, 110 +rjump layer_2360 + +.layer layer_2366 +instr FONT00_INSTR_FLAME_THUNDER +releaserate 221 +legato +portamento 0x81, 16, 255 +.layer layer_236F +notedv PITCH_F2, 0x7F, 72 +rjump layer_236F + +.channel env_ganon_block_sink +ldlayer 0, layer_237B +ldlayer 1, layer_2185 +end + +.layer layer_237B +instr FONT00_INSTR_MECH_CHARGE +env envelope_6660, 247 +.layer layer_2381 +notedv PITCH_F5, 0x3, 95 +notedv PITCH_F4, 0x5, 95 +rjump layer_2381 + +.channel env_crowd_chatter +panweight 0 +ldlayer 0, layer_2398 +ldlayer 1, layer_2392 +end + +.layer layer_2392 +transpose 1 +notepan 0 +rjump layer_239A + +.layer layer_2398 +notepan 127 +.layer layer_239A +instr FONT00_INSTR_CHATTER +env envelope_66F4, 225 +.layer layer_23A0 +notedv PITCH_C4, 0x7D00, 64 +rjump layer_23A0 + +.channel env_water_change +ldlayer 0, layer_23CB +ldlayer 1, layer_23B1 +end + +.layer layer_23AD +transpose 18 +rjump layer_23B3 + +.layer layer_23B1 +transpose 11 +.layer layer_23B3 +instr FONT00_INSTR_WATER_BUBBLES +rjump layer_23BD + +.layer layer_23B7 +instr FONT00_INSTR_WATER_BUBBLES +env envelope_6824, 225 +.layer layer_23BD +releaserate 225 +.layer layer_23BF +notedv PITCH_C2, 0x7D00, 70 +rjump layer_23BF + +.layer layer_23C5 +transpose 6 +rjump layer_23CB + +.layer layer_23C9 +transpose -2 + +.layer layer_23CB +instr FONT00_INSTR_SLIDE_LINK +releaserate 225 +.layer layer_23CF +notedv PITCH_F3, 0x7D00, 74 +rjump layer_23CF + +.channel env_fairy_hide +ldlayer 0, layer_23D9 +end + +.layer layer_23D9 +instr FONT00_INSTR_FAIRY_MAGIC +env envelope_66B8, 251 +legato +portamento 0x85, 27, 255 +notedv PITCH_F5, 0x9, 65 +notedv PITCH_A4, 0x2C, 65 +end + +.channel env_ladder_land +ldlayer 1, layer_14A4 +ldlayer 0, layer_23F2 +end + +.layer layer_23F2 +instr FONT00_INSTR_STICK_ATTACK +transpose 48 +notedv PITCH_EF2, 0x5, 88 +instr FONT00_INSTR_STONE_STRIKE +transpose 0 +notedv PITCH_A3, 0xC, 50 +end + +.channel env_web_bend +instr FONT00_INSTR_CLOTH_TEAR +env envelope_6688 +ldlayer 0, layer_240A +end + +.layer layer_240A +legato +portamento 0x85, 24, 255 +notedv PITCH_F2, 0x18, 100 +notedv PITCH_AF2, 0x30, 100 +end + +.channel env_web_break +instr FONT00_INSTR_CLOTH_TEAR +env envelope_6688 +ldlayer 0, layer_2422 +ldlayer 1, layer_2432 +end + +.layer layer_2422 +legato +ldelay 0x28 +portamento 0x85, 58, 255 +noteldv PITCH_G2, 0x12, 105 +noteldv PITCH_G4, 0x1E, 105 +end + +.layer layer_2432 +portamento 0x81, 20, 255 +notedv PITCH_B2, 0x60, 100 +end + +.channel env_unused2 +ldlayer 0, layer_2451 +ldlayer 1, layer_2445 +vibfreq 220 +vibdepth 53 +end + +.layer layer_2445 +instr FONT00_INSTR_FLAME_THUNDER +env envelope_667C, 247 +legato +.layer layer_244C +notedv PITCH_A1, 0x60, 108 +rjump layer_244C + +.layer layer_2451 +transpose -18 +instr FONT00_INSTR_OCARINA_0 +env envelope_667C, 247 +legato +.layer layer_245A +notedv PITCH_EF3, 0x60, 90 +rjump layer_245A + +.channel env_door_jabu_open +ldlayer 0, layer_2466 +ldlayer 1, layer_2475 +end + +.layer layer_2466 +instr FONT00_INSTR_CLOTH_TEAR +env envelope_6694, 251 +portamento 0x81, 10, 255 +noteldv PITCH_G2, 0x24, 82 +end + +.layer layer_2475 +instr FONT00_INSTR_STEP_WATER +portamento 0x81, 8, 255 +noteldv PITCH_C2, 0x24, 105 +end + +.channel env_door_jabu_close +ldlayer 0, layer_2487 +ldlayer 1, layer_2496 +end + +.layer layer_2487 +instr FONT00_INSTR_CLOTH_TEAR +env envelope_6694, 251 +portamento 0x81, 22, 255 +noteldv PITCH_C1, 0x24, 90 +end + +.layer layer_2496 +instr FONT00_INSTR_STEP_WATER +portamento 0x81, 20, 255 +noteldv PITCH_C1, 0x24, 95 +end + +.channel env_door_wood_creak_unused +ldlayer 0, layer_24A7 +end + +.layer layer_24A5 +transpose 8 + +.layer layer_24A7 +instr FONT00_INSTR_CREAK +notedv PITCH_B1, 0x0, 103 +end + +.channel env_gate_open +ldlayer 0, layer_24B1 +end + +.layer layer_24B1 +instr FONT00_INSTR_MECH_ROTATE +releaserate 240 +notedv PITCH_E3, 0x3C, 75 +.layer layer_24B8 +notedv PITCH_GF3, 0x38, 75 +rjump layer_24B8 + +.channel env_bottle_scoop_water +instr FONT00_INSTR_WATER_SPLISH +ldlayer 0, layer_24C3 +end + +.layer layer_24C3 +portamento 0x82, 39, 127 +notedv PITCH_A3, 0x7F, 100 +end + +.channel env_fish_flop +instr FONT00_INSTR_WATER_SPLISH +cdelay 7 +ldlayer 0, layer_24D2 +end + +.layer layer_24D2 +notedv PITCH_A4, 0x7, 76 +instr FONT00_INSTR_STEP_JABU +portamento 0x81, 39, 127 +notedv PITCH_B5, 0x18, 100 +end + +.channel env_scarecrow_sway +ldlayer 0, layer_24E9 + +.channel chan_fn_24E2 +instr FONT00_INSTR_STEP_GRASS +vibdepth 36 +vibfreq 255 +end + +.layer layer_24E9 +notedv PITCH_F3, 0xA, 90 +notedv PITCH_C4, 0x1E, 90 +end + +.channel env_scarecrow_spin +ldlayer 0, layer_24F7 +call chan_fn_24E2 +end + +.layer layer_24F7 +notedv PITCH_D4, 0xA, 100 +portamento 0x81, 43, 255 +notedv PITCH_E3, 0x5A, 100 +end + +.channel env_bottle_open +ldlayer 0, layer_2506 +end + +.layer layer_2506 +instr FONT00_INSTR_WHIP_CORK +transpose 48 +notedv PITCH_A3, 0x0, 110 +end + +.channel env_jabu_inhale +ldlayer 0, layer_2517 +ldlayer 1, layer_2528 +panweight 48 +end + +.layer layer_2517 +instr FONT00_INSTR_WIND_HOWL_S +env envelope_6674, 232 +legato +portamento 0x85, 46, 255 +.layer layer_2522 +notedv PITCH_C5, 0x3E8, 105 +rjump layer_2522 + +.layer layer_2528 +instr FONT00_INSTR_ROAR_BARK +notedv PITCH_C3, 0x8, 105 +notedv PITCH_G2, 0x0, 105 +end + +.channel env_stone_resonate +ldlayer 0, layer_2545 +ldlayer 1, layer_2538 +end + +.layer layer_2538 +instr FONT00_INSTR_FAIRY +env envelope_67D8, 240 +legato +.layer layer_253F +notedv PITCH_AF3, 0x7D00, 32 +rjump layer_253F + +.layer layer_2545 +instr FONT00_INSTR_WARP +env envelope_67E4, 240 +transpose 15 +legato +.layer layer_254E +notedv PITCH_A4, 0x7D00, 64 +rjump layer_254E + +.channel env_triforce_flash +ldlayer 0, layer_255B +ldlayer 1, layer_2568 +end + +.layer layer_255B +transpose 24 +instr FONT00_INSTR_SYNTH_BUZZ +env envelope_67CC, 241 +notedv PITCH_EF5, 0x120, 42 +end + +.layer layer_2568 +jump layer_210B + +.channel env_ruto_trip +call player_slip_jabu +ldlayer 1, layer_2572 +end + +.layer layer_2572 +instr FONT00_INSTR_STEP_JABU +portamento 0x84, 27, 255 +notedv PITCH_A3, 0xF, 93 +notedv PITCH_F3, 0x10, 93 +notedv PITCH_D3, 0x11, 93 +end + +.channel env_fairy_fly +instr FONT00_INSTR_FAIRY_MAGIC +env envelope_67D8 +panweight 0 +ldlayer 0, layer_258D +end + +.layer layer_258D +legato +portamento 0x81, 48, 255 +.layer layer_2592 +notedv PITCH_D5, 0x20, 50 +rjump layer_2592 + +.channel env_fairy_crash +ldlayer 0, layer_25A7 +ldlayer 1, layer_25BC +cdelay 4 +vibfreq 127 +vibdepthgrad 25, 80, 100 +delay 0x32 +end + +.layer layer_25A7 +instr FONT00_INSTR_STEP_WOOD +releaserate 210 +notedv PITCH_A3, 0x4, 95 +instr FONT00_INSTR_OCARINA_0 +env envelope_6674, 235 +portamento 0x85, 7, 255 +notedv PITCH_G3, 0x38, 70 +end + +.layer layer_25BC +instr FONT00_INSTR_DOOR_WOOD +releaserate 216 +notedv PITCH_C3, 0x4, 95 +jump layer_23D9 + +.channel env_spear_ready +ldlayer 0, layer_25CA +end + +.layer layer_25CA +instr FONT00_INSTR_STICK_ATTACK +transpose 48 +releaserate 245 +notedv PITCH_AF2, 0xD, 90 +end + +.channel env_unused3 +ldlayer 0, layer_25EC +ldlayer 1, layer_25DB +end + +.layer layer_25DB +instr FONT00_INSTR_WATER_BUBBLES +env envelope_66F4, 160 +legato +portamento 0x85, 26, 255 +.layer layer_25E6 +notedv PITCH_GF3, 0x3E8, 80 +rjump layer_25E6 + +.layer layer_25EC +instr FONT00_INSTR_WATER_FLOWING +env envelope_66F4, 160 +transpose 48 +legato +portamento 0x85, 36, 255 +.layer layer_25F9 +notedv PITCH_F4, 0x3E8, 75 +rjump layer_25F9 + +.channel env_water_drip_unused +ldlayer 0, layer_2608 +ldlayer 1, layer_2606 +end + +.layer layer_2606 +transpose 5 + +.layer layer_2608 +instr FONT00_INSTR_WATER_DRIP +env envelope_66F4, 211 +legato +portamento 0x81, 27, 255 +.layer layer_2613 +notedv PITCH_G4, 500, 80 +rjump layer_2613 + +.channel env_windmill_gear +instr FONT00_INSTR_CREAK +panweight 64 +ldlayer 0, layer_2621 +end + +.layer layer_2621 +portamento 0x83, 10, 255 +.layer layer_2625 +notedv PITCH_C2, 0x20, 96 +rjump layer_2625 + +.channel env_bush_sway +ldlayer 0, layer_2638 +ldlayer 1, layer_2631 +end + +.layer layer_2631 +instr FONT00_INSTR_CREAK +notedv PITCH_E3, 0x18, 65 +transpose 18 + +.layer layer_2638 +instr FONT00_INSTR_STEP_GRASS +env envelope_6688, 251 +notedv PITCH_B2, 0xE, 95 +notedv PITCH_C4, 0x14, 100 +notedv PITCH_BF2, 0x11, 102 +notedv PITCH_BF3, 0x50, 103 +end + +.channel env_horse_demo_gallop +instr FONT00_INSTR_HORSE_GALLOP +ldlayer 0, layer_2651 +end + +.layer layer_2651 +notedv PITCH_C4, 0x27, 110 +rjump layer_2651 + +.channel env_elevator_geared_move +instr FONT00_INSTR_MECH_CHARGE +gain 20 +ldlayer 0, layer_265E +end + +.layer layer_265E +transpose 48 +legato +.layer layer_2661 +notedv PITCH_E3, 0x7D00, 100 +rjump layer_2661 + +.channel env_elevator_geared_stop +ldlayer 0, layer_2671 +ldlayer 1, layer_2677 +ldlayer 2, layer_2685 +end + +.layer layer_2671 +instr FONT00_INSTR_SLAM_LIGHT +notedv PITCH_F3, 0x40, 95 +end + +.layer layer_2677 +instr FONT00_INSTR_SLAM_GUNSHOT +env envelope_66B0, 250 +portamento 0x81, 31, 200 +notedv PITCH_C3, 0x3C, 100 +end + +.layer layer_2685 +instr FONT00_INSTR_MECH_CHARGE +transpose 48 +portamento 0x81, 39, 255 +notedv PITCH_GF2, 0x34, 96 +end + +.channel env_treasure_warp +ldlayer 0, layer_269B +ldlayer 1, layer_26B3 +ldlayer 2, layer_26C2 +end + +.layer layer_269B +instr FONT00_INSTR_FAIRY +env envelope_6694, 235 +portamento 0x83, 39, 255 +loop 7 +notedv PITCH_G4, 0x40, 64 +loopend +portamento 0x81, 41, 255 +notedv PITCH_A4, 0x70, 64 +end + +.layer layer_26B3 +transpose 16 +instr FONT00_INSTR_WARP +env envelope_6694, 235 +loop 7 +notedv PITCH_GF5, 0x40, 50 +loopend +end + +.layer layer_26C2 +ldelay 0x109 +instr FONT00_INSTR_SYNTH +env envelope_67CC, 235 +notedv PITCH_D3, 0x7F, 105 +end + +.channel env_door_unlock +gain 20 +ldlayer 0, layer_26D8 +ldlayer 1, layer_26DE +end + +.layer layer_26D8 +instr FONT00_INSTR_CHAIN +notedv PITCH_GF4, 0x4C, 50 +end + +.layer layer_26DE +instr FONT00_INSTR_SWORD_STRIKE +notedv PITCH_E2, 0x8, 84 +instr FONT00_INSTR_SWORD_SHEATHE +notedv PITCH_DF4, 0x14, 105 +end + +.channel env_trap_blade_move +ldlayer 0, layer_26F0 +ldlayer 1, layer_26FA +end + +.layer layer_26F0 +instr FONT00_INSTR_SWORD_DRAW +portamento 0x81, 12, 64 +notedv PITCH_BF2, 0x7F, 85 +end + +.layer layer_26FA +instr FONT00_INSTR_CHAIN +notedv PITCH_D3, 0x30, 81 +end + +.channel env_fairy_heal_old +instr FONT00_INSTR_SHIMMER +env envelope_66F4 +releaserate 221 +ldlayer 0, layer_2713 +ldlayer 1, layer_2711 +ldlayer 2, layer_271E +end + +.layer layer_2711 +transpose 4 + +.layer layer_2713 +legato +portamento 0x81, 43, 255 +.layer layer_2718 +notedv PITCH_F4, 0x190, 48 +rjump layer_2718 + +.layer layer_271E +transpose 48 +env envelope_67D8, 221 +legato +portamento 0x81, 50, 255 +.layer layer_2729 +notedv PITCH_C5, 0x190, 64 +rjump layer_2729 + +.channel env_great_fairy_appear +ldi 129 +.channel chan_2731 +stseq 0, layer_2745+1 +instr FONT00_INSTR_FAIRY +env envelope_66FC +releaserate 221 +ldlayer 0, layer_2743 +ldlayer 1, layer_2745 +end + +.layer layer_2743 +transpose 24 + +.layer layer_2745 +portamento 0x81, 31, 255 +notedv PITCH_G3, 0xF0, 80 +end + +.channel env_great_fairy_vanish +ldi 130 +rjump chan_2731 + +.channel env_trap_eye_fire +ldlayer 0, layer_2756 +end + +.layer layer_2756 +instr FONT00_INSTR_SYNTH +env envelope_67CC, 245 +portamento 0x81, 19, 80 +notedv PITCH_AF3, 0x6E, 105 +end + +.channel env_gears_unused +instr FONT00_INSTR_DOOR_METAL +env envelope_6674 +panweight 72 +ldlayer 0, layer_276F +end + +.layer layer_276F +legato +.layer layer_2770 +notedv PITCH_F3, 0x7D00, 88 +rjump layer_2770 + +.channel env_wall_move_unused +instr FONT00_INSTR_DOOR_METAL +ldlayer 0, layer_2781 +ldlayer 1, layer_277F +end + +.layer layer_277F +transpose -6 + +.layer layer_2781 +legato +portamento 1, 15, 48 +.layer layer_2786 +notedv PITCH_E3, 32700, 75 +rjump layer_2786 + +.channel env_treasure_flash +ldlayer 0, layer_2790 +end + +.layer layer_2790 +instr FONT00_INSTR_WARP +env envelope_6638, 251 +transpose 36 +notedv PITCH_D3, 0xD, 98 +notedv PITCH_D4, 0x64, 98 +end + +.channel env_windmill_blade +instr FONT00_INSTR_CREAK +ldlayer 0, layer_27A5 +end + +.layer layer_27A5 +legato +transpose 48 +notedv PITCH_C2, 32700, 100 +rjump layer_27A5 + +.channel env_grotto_exit +rvrbidx 1 + +.channel env_warp_unused +ldi 129 +.channel chan_27B2 +stseq 0, layer_27D3+1 +panweight 64 +ldlayer 0, layer_27CC +ldlayer 1, layer_27C8 +ldlayer 2, layer_27C2 +end + +.layer layer_27C2 +transpose 8 +notepan 104 +rjump layer_27CC + +.layer layer_27C8 +transpose 4 +notepan 24 + +.layer layer_27CC +instr FONT00_INSTR_WARP +env envelope_66F4, 230 +legato +.layer layer_27D3 +portamento 0x81, 58, 255 +.layer layer_27D7 +notedv PITCH_A5, 0x7D0, 75 +rjump layer_27D7 + +.channel env_pot_break +ldlayer 0, layer_27E4 +ldlayer 1, layer_27E8 +end + +.layer layer_27E4 +transpose 36 +rjump layer_27EA + +.layer layer_27E8 +transpose 48 +.layer layer_27EA +instr FONT00_INSTR_POTTERY_ELECTRIC +notedv PITCH_BF3, 0x0, 75 +end + +.channel env_pot_drop +ldlayer 0, layer_27F7 +ldlayer 1, layer_998 +end + +.layer layer_27F7 +transpose 48 +jump layer_992 + +.channel env_goddess_fly +call chan_fn_2823 +ldlayer 0, layer_280A +ldlayer 1, layer_2816 +vibfreq 128 +vibdepth 16 +end + +.layer layer_280A +instr FONT00_INSTR_MECH_CHARGE +env envelope_6674, 245 +.layer layer_2810 +notedv PITCH_D5, 0x7D00, 60 +rjump layer_2810 + +.layer layer_2816 +instr FONT00_INSTR_WIND_HOWL_S +env envelope_66F4, 245 +legato +.layer layer_281D +notedv PITCH_DF4, 0x7D00, 75 +rjump layer_281D + +.channel chan_fn_2823 +gain 12 +ldi 25 +stio 1 +end + +.channel env_triforce_aura +instr FONT00_INSTR_SHIMMER +ldlayer 0, layer_2832 +ldlayer 1, layer_283C +end + +.layer layer_2832 +env envelope_67D8, 230 +.layer layer_2836 +notedv PITCH_AF4, 0x7D00, 50 +rjump layer_2836 + +.layer layer_283C +transpose 48 +env envelope_67D8, 230 +.layer layer_2842 +notedv PITCH_A3, 0x7D00, 32 +rjump layer_2842 + +.channel env_triforce_glow +ldlayer 0, layer_2853 +ldlayer 1, layer_284F +end + +.layer layer_284F +transpose 16 +rjump layer_2855 + +.layer layer_2853 +transpose 12 +.layer layer_2855 +instr FONT00_INSTR_WARP +env envelope_66F4, 230 +legato +.layer layer_285C +notedv PITCH_F5, 0x7D00, 35 +rjump layer_285C + +.channel env_deku_tree_death +gain 15 +ldlayer 0, layer_286D +ldlayer 1, layer_287C +end + +.layer layer_286B +transpose 4 + +.layer layer_286D +instr FONT00_INSTR_MECH_CHARGE +env envelope_66FC, 170 +portamento 0x81, 32, 145 +notedv PITCH_D3, 0x244, 105 +end + +.layer layer_287C +instr FONT00_INSTR_CLOTH_TEAR +env envelope_66FC, 170 +portamento 0x81, 5, 145 +notedv PITCH_B0, 0x244, 110 +end + +.channel env_jabu_platform_rise +ldi 129 +stseq 0, layer_28AA+1 +.channel chan_2891 +ldlayer 0, layer_28A3 +ldlayer 1, layer_289C +vibfreq 111 +vibdepth 10 +end + +.layer layer_289C +transpose -12 +instr FONT00_INSTR_OCARINA_0 +jump layer_28A5 + +.layer layer_28A3 +instr FONT00_INSTR_FLAME_THUNDER +.layer layer_28A5 +env envelope_667C, 231 +legato +.layer layer_28AA +portamento 0x81, 12, 25 +.layer layer_28AE +notedv PITCH_D3, 0xCB2, 74 +rjump layer_28AE + +.channel env_jabu_platform_fall +ldi 130 +stseq 0, layer_28AA+1 +rjump chan_2891 + +.channel env_door_jabu_unlock +ldi 129 +.channel chan_28BE +stseq 0, layer_28D2+1 +instr FONT00_INSTR_SYNTH +env envelope_6688 +ldlayer 0, layer_28D2 +ldlayer 1, layer_28D0 +delay 0x14 +end + +.layer layer_28D0 +instr FONT00_INSTR_STEP_WATER + +.layer layer_28D2 +portamento 0x81, 17, 255 +releaserate 251 +notedv PITCH_D1, 0x14, 80 +end + +.channel env_door_jabu_lock +ldi 130 +rjump chan_28BE + +.channel env_door_time_stop +ldlayer 0, layer_1B2E +ldlayer 1, layer_1F1A +end + +.channel env_stone_restore +instr FONT00_INSTR_WARP +ldlayer 0, layer_2913 +ldlayer 1, layer_2900 +ldlayer 2, layer_2922 +vibfreq 128 +vibdepthgrad 32, 0, 55 +ldi 1 +call delay_varyingvol +vibdepth 0 +end + +.layer layer_2900 +instr FONT00_INSTR_FAIRY +env envelope_67E4, 200 +portamento 0x81, 38, 180 +notedv PITCH_C4, 0x384, 32 +end + +.layer layer_290F +transpose 27 +rjump layer_2915 + +.layer layer_2913 +transpose 15 +.layer layer_2915 +env envelope_67E4, 200 +portamento 0x81, 50, 180 +notedv PITCH_C5, 0x384, 80 +end + +.layer layer_2922 +releaserate 200 +notedv PITCH_C3, 0x258, 64 +transpose 27 +env envelope_66F4, 221 +notedv PITCH_C5, 0x12C, 70 +end + +.channel env_medal_acquire +ldlayer 0, layer_2937 +end + +.layer layer_2937 +instr FONT00_INSTR_SHIMMER +env envelope_6808, 240 +transpose 48 +legato +portamento 0x85, 46, 255 +notedv PITCH_GF4, 0x50, 80 +notedv PITCH_C4, 0xD2, 80 +.layer layer_294B +notedv PITCH_C4, 0x113, 80 +rjump layer_294B + +.channel env_unused4 +ldlayer 0, layer_2958 +ldlayer 1, layer_54B +end + +.layer layer_2958 +instr FONT00_INSTR_SLAM_GUNSHOT +env envelope_66B0, 250 +portamento 0x83, 38, 200 +notedv PITCH_AF2, 0x3, 95 +notedvg PITCH_BF2, 0x9, 95, 100 +end + +.channel env_light_arrow_acquire +ldlayer 0, layer_296E +end + +.layer layer_296E +instr FONT00_INSTR_SHIMMER +env envelope_6800, 240 +transpose 48 +legato +portamento 0x85, 32, 255 +notedv PITCH_F3, 0x50, 80 +notedv PITCH_G4, 0x50, 80 +notedv PITCH_G4, 0x208, 80 +notedv PITCH_C4, 0xD2, 80 +.layer layer_2989 +notedv PITCH_F3, 0x64, 80 +rjump layer_2989 + +.channel env_earthquake +ldlayer 0, layer_299C +ldlayer 1, layer_2998 +ldlayer 2, layer_29AD +end + +.layer layer_2998 +stereo 20 + +.layer layer_299A +transpose -6 + +.layer layer_299C +instr FONT00_INSTR_MECH_CHARGE +env envelope_66FC, 211 +legato +portamento 0x81, 46, 255 +.layer layer_29A7 +notedv PITCH_A4, 0xC8, 77 +rjump layer_29A7 + +.layer layer_29AD +ldelay 0x64 + +.layer layer_29AF +instr FONT00_INSTR_EXPLOSION_0 +env envelope_66FC, 221 +notedv PITCH_A2, 0xCF, 72 +.layer layer_29B9 +notedv PITCH_F3, 0x6F, 80 +notedv PITCH_C3, 0xA8, 84 +notedv PITCH_D3, 0x61, 68 +rjump layer_29B9 + +.channel env_trap_crystal +ldi 40 +stio 1 +ldlayer 0, layer_29E3 +ldlayer 1, layer_29D2 +ldlayer 2, layer_29D4 +end + +.layer layer_29D2 +transpose -4 + +.layer layer_29D4 +instr FONT00_INSTR_SHIMMER +env envelope_66F4, 241 +portamento 0x81, 39, 255 +notedv PITCH_EF3, 0xC6, 90 +end + +.layer layer_29E3 +ldelay 0xBC +instr FONT00_INSTR_SYNTH +portamento 0x81, 3, 32 +notedv PITCH_C2, 0x40, 105 +end + +.channel env_sage_warp +instr FONT00_INSTR_WARP +ldlayer 0, layer_29FC +ldlayer 1, layer_2124 +ldlayer 2, layer_2A01 +end + +.layer layer_29FC +transpose 30 +jump layer_2132 + +.layer layer_2A01 +transpose 51 +jump layer_2149 +.layer layer_2A06 +instr FONT00_INSTR_EYE_OF_TRUTH +releaserate 221 +portamento 0x84, 22, 127 +notedv PITCH_A4, 0x60, 85 +notedv PITCH_B4, 0x7F, 95 +end + +.channel env_sage_charge +instr FONT00_INSTR_SHIMMER +ldlayer 0, layer_2A27 +ldlayer 1, layer_2A36 +ldlayer 2, layer_2A3F +vibdepth 40 +vibfreqgrad 148, 240, 100 +end + +.layer layer_2A27 +instr FONT00_INSTR_FLAME_THUNDER +env envelope_66F4, 221 +portamento 0x81, 39, 255 +notedv PITCH_B5, 0x2E4, 95 +end + +.layer layer_2A36 +portamento 0x81, 27, 255 +notedv PITCH_B4, 0x2E4, 65 +end + +.layer layer_2A3F +transpose 48 +releaserate 180 +portamento 0x81, 27, 255 +notedv PITCH_B4, 0x21C, 62 +transpose 0 +instr FONT00_INSTR_SLIDE_LINK +env envelope_66F4, 221 +portamento 0x81, 39, 255 +notedv PITCH_B5, 0xC8, 85 +end + +.channel env_time_travel_end +ldi 30 +stio 1 +ldlayer 0, layer_2A6D +ldlayer 1, layer_2A7B +ldlayer 2, layer_2A8A +vibfreq 251 +vibdepth 6 +end + +.layer layer_2A6D +instr FONT00_INSTR_WARP +transpose 24 +env envelope_66F4, 230 +.layer layer_2A75 +notedv PITCH_A4, 0x7D00, 64 +rjump layer_2A75 + +.layer layer_2A7B +instr FONT00_INSTR_WATER_FLOWING +transpose 48 +legato +env envelope_66F4, 180 +.layer layer_2A84 +notedv PITCH_F5, 0x7D00, 40 +rjump layer_2A84 + +.layer layer_2A8A +instr FONT00_INSTR_SHIMMER +env envelope_66F4, 180 +legato +.layer layer_2A91 +notedv PITCH_C5, 0x7D00, 64 +rjump layer_2A91 + +.channel env_jabu_platform_rise_stop +gain 20 +ldlayer 0, layer_2AA8 +ldlayer 1, layer_2AA0 +end + +.layer layer_2AA0 +instr FONT00_INSTR_STEP_WATER +notedv PITCH_G1, 0x1E, 80 +jump layer_1B35 + +.layer layer_2AA8 +instr FONT00_INSTR_BLOCK_LOCK +portamento 0x81, 32, 127 +notedv PITCH_A3, 0x64, 110 +end + +.channel env_jabu_platform_fall_stop +gain 10 +ldlayer 0, layer_1B2E +ldlayer 1, layer_2AC6 +ldlayer 2, layer_2ABE +end + +.layer layer_2ABE +instr FONT00_INSTR_STEP_WATER +notedv PITCH_D1, 0x32, 80 +jump layer_1B35 + +.layer layer_2AC6 +instr FONT00_INSTR_BLOCK_LOCK +notedv PITCH_D3, 0x78, 110 +end + +.channel env_goron_fall +ldlayer 0, layer_2AD4 +vibdepth 4 +vibfreq 58 +end + +.layer layer_2AD4 +transpose 12 +instr FONTANY_INSTR_SINE +env envelope_66D0, 248 +portamento 0x81, 56, 255 +notedv PITCH_F3, 0x7F, 60 +end + +.channel env_spell_fire_stance +ldlayer 0, layer_3E5 +ldlayer 1, layer_747 +end + +.channel env_ice_melt +ldlayer 0, layer_2B01 +ldlayer 1, layer_2AF2 +end + +.layer layer_2AF2 +instr FONT00_INSTR_SLIDE_BLOCK +env envelope_66FC, 225 +portamento 0x81, 62, 255 +notedv PITCH_C5, 0xAA, 96 +end + +.layer layer_2B01 +instr FONT00_INSTR_BOMB +env envelope_66FC, 225 +portamento 0x81, 51, 255 +notedv PITCH_A2, 0xAA, 96 +end + +.channel env_fire_pillar +ldlayer 0, layer_2C60 +end + +.channel env_unused5 +instr FONT00_INSTR_DOOR_METAL +env envelope_6610 +ldlayer 0, layer_2B1D +end + +.layer layer_2B1D +notedv PITCH_GF3, 0x9, 110 +loop 32 +notedv PITCH_AF3, 0x8, 115 +loopend +notedv PITCH_BF3, 0xB, 115 +end + +.channel env_magic_vanish +ldlayer 0, layer_2B31 +ldlayer 1, layer_2B39 +end + +.layer layer_2B31 +instr FONT00_INSTR_FAIRY +env envelope_66FC, 195 +rjump layer_2B41 + +.layer layer_2B39 +instr FONT00_INSTR_SHIMMER +env envelope_66FC, 195 +transpose 48 +.layer layer_2B41 +portamento 0x81, 44, 255 +notedv PITCH_E5, 0x64, 85 +end + +.channel env_ocarina_warp +ldi 129 +stseq 0, layer_2B95+1 +stseq 0, layer_2BA6+1 +ldlayer 0, layer_2B5D +ldlayer 1, layer_2B9F +ldlayer 2, layer_2B86 +end + +.layer layer_2B5D +ldelay 0x172 +end + +.channel env_ocarina_arrive +ldi 130 +stseq 0, layer_2B95+1 +stseq 0, layer_2BA6+1 +ldlayer 0, layer_2B5D +ldlayer 1, layer_2B9F +ldlayer 2, layer_2B86 +end + +.channel env_fairy_heal +ldi 129 +stseq 0, layer_2B95+1 +stseq 0, layer_2BA6+1 +ldlayer 0, layer_2B8C +ldlayer 1, layer_2B9F +end + +.layer layer_2B86 +instr FONT00_INSTR_FAIRY_MAGIC +transpose -12 +rjump layer_2B90 + +.layer layer_2B8C +instr FONT00_INSTR_SHIMMER +transpose 48 +.layer layer_2B90 +legato +env envelope_67D8, 221 +.layer layer_2B95 +portamento 0x81, 27, 255 +.layer layer_2B99 +notedv PITCH_C5, 500, 85 +rjump layer_2B99 + +.layer layer_2B9F +instr FONT00_INSTR_FAIRY_MAGIC +legato +env envelope_67D8, 221 +.layer layer_2BA6 +portamento 0x81, 51, 255 +.layer layer_2BAA +notedv PITCH_B5, 500, 85 +rjump layer_2BAA + +.channel env_door_boss_unlock +gain 20 +ldlayer 0, layer_2BC7 +ldlayer 1, layer_2BBC +ldlayer 2, layer_26D8 +end + +.layer layer_2BBC +instr FONT00_INSTR_SWORD_STRIKE +notedv PITCH_E2, 0xF, 84 +instr FONT00_INSTR_CHAIN +notedv PITCH_C4, 0x3D, 66 +end + +.layer layer_2BC7 +instr FONT00_INSTR_SWORD_STRIKE +notedv PITCH_E1, 0x8, 84 +transpose 48 +notedv PITCH_EF2, 0x0, 80 +end + +.channel env_crate_small_break +ldlayer 0, layer_2BD9 +ldlayer 1, layer_1F7B +end + +.layer layer_2BD9 +transpose -12 +jump layer_1F6E + +.channel env_unused6 +ldlayer 1, layer_1F1C + +.channel env_crate_small_drop +ldlayer 0, layer_2BE5 +end + +.layer layer_2BE5 +instr FONT00_INSTR_STICK_ATTACK +notedv PITCH_C3, 0x4, 100 +notedv PITCH_G2, 0x8, 100 +end + +.channel env_ruto_rebound_jabu +ldlayer 0, layer_561 +ldlayer 1, layer_2958 +end + +.channel env_door_creak_rumble +gain 15 +ldlayer 0, layer_286B +ldlayer 1, layer_24A5 +end + +.channel env_night_howl +ldi 25 +stio 1 +ldlayer 0, layer_2C05 +end + +.layer layer_2C05 +instr FONT00_INSTR_ANIMALS_1 +transpose 48 +notedv PITCH_G3, 0x0, 70 +end + +.channel env_jabu_groan +ldlayer 0, layer_137D +ldlayer 1, layer_1361 +ldlayer 2, layer_299C +jump chan_135C + +.channel env_frog_jump +ldlayer 0, layer_2C20 +ldlayer 1, layer_2C2A +end + +.layer layer_2C20 +instr FONT00_INSTR_ANIMALS_0 +transpose 48 +releaserate 241 +notedv PITCH_C3, 0x2B, 100 +end + +.layer layer_2C2A +instr FONTANY_INSTR_SQUARE +env envelope_65D8, 251 +portamento 0x81, 15, 255 +notedv PITCH_C5, 0x28, 45 +end + +.channel env_ice_freeze_old +ldlayer 0, layer_2C47 +ldlayer 1, layer_2C3F +end + +.layer layer_2C3F +instr FONT00_INSTR_EXPLOSION_0 +env envelope_667C, 240 +rjump layer_2C4E + +.layer layer_2C47 +instr FONT00_INSTR_FIRE_WIND +legato +portamento 0x81, 32, 255 +.layer layer_2C4E +notedv PITCH_C2, 0x190, 105 +rjump layer_2C4E + +.channel env_fire_wall +ldlayer 1, layer_2C62 +ldi 88 +stseq 0, chan_2287+1 +jump chan_2267 + +.layer layer_2C60 +transpose 6 + +.layer layer_2C62 +instr FONT00_INSTR_FIRE_WALL +env envelope_667C, 230 +legato +portamento 0x85, 3, 255 +.layer layer_2C6D +notedv PITCH_E1, 0x55, 80 +notedv PITCH_C1, 0x20, 80 +rjump layer_2C6D + +.channel env_wood_rebound +instr FONT00_INSTR_STICK_ATTACK +ldlayer 0, layer_2C7E +ldlayer 1, layer_13EE +end + +.layer layer_2C7E +notedv PITCH_GF3, 0xD, 100 +notedv PITCH_A2, 0x0, 72 +end + +.channel env_water_drip_unused2 +ldi 80 +stio 1 +ldlayer 0, layer_2C91 +ldlayer 1, layer_2C8F +end + +.layer layer_2C8F +transpose -1 + +.layer layer_2C91 +ldelay 0x30 +instr FONT00_INSTR_WATER_DRIP +notedv PITCH_GF3, 0x40, 105 +end + +.channel env_jabu_breathe +ldlayer 0, layer_2C9D +end + +.layer layer_2C9D +instr FONT00_INSTR_ROAR_BARK +releaserate 240 +portamento 0x83, 8, 255 +notedvg PITCH_C2, 0xA8, 85, 5 +notedv PITCH_C1, 0x96, 85 +end + +.channel env_dalm_block_hit +gain 10 +ldlayer 0, layer_1F6E +ldlayer 1, layer_1F7B +ldlayer 2, layer_2B31 +end + +.channel env_boulder_roll +ldlayer 0, layer_2CC8 +ldlayer 1, layer_2CC2 +end + +.layer layer_2CC2 +instr FONT00_INSTR_MECH_CHARGE +transpose 15 +rjump layer_2CCA + +.layer layer_2CC8 +instr FONT00_INSTR_ROLL_BOULDER +.layer layer_2CCA +legato +releaserate 235 +portamento 0x81, 22, 175 +.layer layer_2CD1 +notedv PITCH_C3, 0x60, 95 +rjump layer_2CD1 + +.channel env_elevator_groan_unused +ldlayer 0, layer_2CDF +ldlayer 1, layer_2CDD +end + +.layer layer_2CDD +transpose -24 + +.layer layer_2CDF +instr FONT00_INSTR_MECH_CHARGE +env envelope_6674, 251 +legato +portamento 1, 36, 127 +.layer layer_2CEA +notedv PITCH_F5, 32700, 95 +rjump layer_2CEA + +.channel env_diamond_switch_on +call env_guard_attention +jump env_treasure_flash + +.channel env_kakariko_fire +panweight 48 +ldlayer 2, layer_2357 +jump env_fire_wall + +.channel env_rainbow_bridge_appear +call env_triforce_aura +.channel chan_2D01 +ldlayer 1, layer_2937 +ldi 100 +call delay_varyingvol +ldlayer 2, layer_2937 +ldi 100 +call delay_varyingvol +rjump chan_2D01 + +.channel env_flying_old +ldlayer 1, layer_2D25 +ldlayer 2, layer_2D23 +ldi 102 +stseq 0, chan_2287+1 +jump chan_2267 +end + +.layer layer_2D23 +transpose -9 + +.layer layer_2D25 +legato +instr FONT00_INSTR_WIND_HOWL_S +env envelope_6818, 241 +portamento 1, 44, 127 +.layer layer_2D30 +notedv PITCH_B4, 32700, 80 +rjump layer_2D30 + +.channel env_flying_end_old +ldlayer 0, layer_2D3A +end + +.layer layer_2D3A +transpose 12 +legato +instr FONT00_INSTR_WIND_HOWL_S +env envelope_6694, 221 +portamento 0x85, 48, 255 +notedv PITCH_D4, 0x24, 105 +notedv PITCH_G5, 0x64, 105 +end + +.channel env_deku_sprout_grow +ldlayer 0, layer_2D55 +ldlayer 1, layer_599 +end + +.layer layer_2D55 +instr FONT00_INSTR_EXPLOSION_0 +env envelope_6688, 230 +portamento 0x81, 10, 255 +notedv PITCH_A4, 0x46, 95 +end + +.channel env_desert_storm +ldlayer 0, layer_2D6E +ldlayer 1, layer_2D6A +end + +.layer layer_2D6A +transpose 27 +rjump layer_2D70 + +.layer layer_2D6E +transpose 36 +.layer layer_2D70 +legato +instr FONT00_INSTR_FIRE_WIND +env envelope_6674, 200 +portamento 0x85, 56, 255 +.layer layer_2D7B +notedv PITCH_B5, 500, 58 +notedv PITCH_E5, 350, 58 +rjump layer_2D7B + +.channel env_triforce_mark +ldlayer 0, layer_255B +ldlayer 1, layer_2D8F +ldlayer 2, layer_2790 +end + +.layer layer_2D8F +instr FONT00_INSTR_FAIRY +env envelope_66FC, 195 +portamento 0x81, 0, 255 +notedv PITCH_F2, 0x7F, 85 +end + +.channel env_grave_explode +gain 20 +ldlayer 0, layer_1A36 +ldlayer 1, layer_1F6E +ldlayer 2, layer_1F7B +end + +.channel env_obj_drop_water +ldlayer 0, layer_1ACE +end + +.channel env_obj_lift_water +ldlayer 0, layer_2DB1 +end + +.layer layer_2DB1 +instr FONT00_INSTR_WATER_SPLISH +notedv PITCH_B4, 0x9, 100 +instr FONT00_INSTR_WATER_SPLASH +env envelope_664C, 240 +notedv PITCH_A4, 0x6, 90 +notedv PITCH_B4, 0x22, 80 +end + +.channel env_ganondorf_cloak +instr FONT00_INSTR_CLOAK +ldlayer 0, layer_2DC9 +end + +.layer layer_2DC9 +portamento 0x81, 27, 127 +notedv PITCH_F3, 0x64, 100 +end + +.channel env_dig +ldlayer 0, layer_3CC +ldlayer 1, layer_599 +end + +.channel env_lab_bubbles +ldlayer 0, layer_2DDC +end + +.layer layer_2DDC +instr FONT00_INSTR_WATER_BUBBLES +releaserate 200 +notedv PITCH_G3, 0x40, 55 +end + +.channel env_ice_break_old +instr FONT00_INSTR_CHATTER +env envelope_65D8 +ldlayer 0, layer_2DF0 +ldlayer 1, layer_2DF6 +end + +.layer layer_2DF0 +transpose 48 +notedv PITCH_C4, 0x48, 94 +end + +.layer layer_2DF6 +transpose 48 +notedv PITCH_B4, 0x48, 112 +end + +.channel env_frog_grow +ldlayer 0, layer_2E00 +end + +.layer layer_2E00 +instr FONTANY_INSTR_BELL +env envelope_6610, 251 +portamento 0x83, 0, 255 +notedv PITCH_AF2, 0x2C, 60 +notedv PITCH_D3, 0x2C, 60 +notedv PITCH_G3, 0x2C, 60 +end + +.channel env_water_flow +panweight 48 +ldlayer 0, layer_23C9 +ldlayer 1, layer_23B7 +end + +.channel env_gate_large_open +ldlayer 0, layer_2E21 +end + +.layer layer_2E21 +instr FONT00_INSTR_DOOR_METAL +transpose 48 +notedv PITCH_C3, 0x0, 110 +end + +.channel env_goddess_face_break +call env_bwall_break +ldlayer 2, layer_1A30 +end + +.channel env_goddess_face_explode +ldlayer 0, layer_1A36 +ldlayer 1, layer_299A +end + +.channel env_goddess_face_crumble +ldlayer 0, layer_29AD +ldlayer 1, layer_29AF +end + +.channel env_trap_blade_move_old +ldlayer 0, layer_2E45 +ldlayer 1, layer_26FA +end + +.layer layer_2E45 +instr FONT00_INSTR_SWORD_DRAW +portamento 0x81, 24, 64 +notedv PITCH_G2, 0x7F, 85 +end + +.channel env_unused7 +instr FONT00_INSTR_CHATTER +ldlayer 0, layer_2E55 +end + +.layer layer_2E55 +transpose 48 +notedv PITCH_A3, 0xA, 94 +end + +.channel env_warp_lower +ldi 130 +jump chan_27B2 + +.channel env_sage_chamber_ambient +ldi 32 +stio 1 +ldlayer 0, layer_2E67 +end + +.layer layer_2E67 +instr FONT00_INSTR_WATER_DRIP +.layer layer_2E69 +notedv PITCH_B0, 0x0, 70 +rjump layer_2E69 + +.channel env_sage_chamber_energy +ldi 32 +stio 1 +ldlayer 0, layer_2E75 +end + +.layer layer_2E75 +instr FONT00_INSTR_WIND_HOWL_S +env envelope_6710, 251 +legato +portamento 0x81, 39, 255 +.layer layer_2E80 +notedv PITCH_C3, 0xFA, 110 +rjump layer_2E80 + +.channel env_dog_bark +ldlayer 0, layer_2E8A +end + +.layer layer_2E8A +instr FONT00_INSTR_ROAR_BARK +transpose 48 +notedv PITCH_C4, 0x0, 100 +end + +.channel env_zelda_cast_spell +instr FONT00_INSTR_WARP +gain 15 +ldlayer 1, layer_290F +ldlayer 0, layer_2EA0 +ldlayer 2, layer_2EAF +end + +.layer layer_2EA0 +instr FONT00_INSTR_FAIRY +env envelope_67E4, 200 +portamento 0x81, 50, 180 +notedv PITCH_C5, 0xC8, 110 +end + +.layer layer_2EAF +releaserate 200 +notedv PITCH_C4, 0xC8, 115 +end + +.channel env_rain +instr FONTANY_INSTR_DRUM +panweight 0 +ldlayer 0, layer_2EC1 +ldlayer 1, layer_2EC8 +end + +.layer layer_2EC1 +legato +.layer layer_2EC2 +notedv FONT00_DRUM_RAIN_1, 32700, 80 +rjump layer_2EC2 + +.layer layer_2EC8 +legato +.layer layer_2EC9 +notedv FONT00_DRUM_RAIN_0, 32700, 80 +rjump layer_2EC9 + +.channel env_door_metal_open +ldlayer 0, layer_2ED3 +end + +.layer layer_2ED3 +instr FONT00_INSTR_DOOR_METAL +transpose 48 +notedv PITCH_D4, 0x0, 110 +end + +.channel env_door_metal_close +ldlayer 0, layer_2EDF +end + +.layer layer_2EDF +instr FONT00_INSTR_DOOR_METAL +transpose 48 +notedv PITCH_G3, 0x0, 110 +end + +.channel env_whirlpool +ldlayer 0, layer_23C5 +ldlayer 1, layer_23AD +end + +.channel env_tower_break +gain 10 +ldlayer 0, layer_2EFA +ldlayer 1, layer_2F0A +ldlayer 2, layer_1F41 +end + +.layer layer_2EFA +instr FONT00_INSTR_EXPLOSION_0 +releaserate 221 +notedv PITCH_C4, 0xC, 82 +portamento 0x81, 27, 255 +notedv PITCH_F2, 0x91, 105 +end + +.layer layer_2F0A +instr FONT00_INSTR_MECH_CHARGE +releaserate 221 +notedv PITCH_C5, 0xC, 82 +portamento 0x81, 39, 255 +notedv PITCH_F3, 0x91, 105 +end + +.channel env_cow_moo +instr FONT00_INSTR_FIRE_COW +ldlayer 0, layer_2F20 +end + +.layer layer_2F20 +transpose 48 +notedv PITCH_C4, 0x0, 100 +end + +.channel env_obj_break_unused +ldlayer 0, layer_2F2D +ldlayer 1, layer_2F38 +end + +.layer layer_2F2D +instr FONT00_INSTR_DOOR_METAL +transpose 48 +notedv PITCH_G5, 0xD, 66 +notedv PITCH_D5, 0x1A, 66 +end + +.layer layer_2F38 +instr FONT00_INSTR_POTTERY_ELECTRIC +transpose 48 +notedv PITCH_A3, 0x0, 68 +notedv PITCH_C4, 0x0, 68 +end + +.channel env_rock_barrier_hit +ldlayer 3, layer_1E0A +call env_grave_explode +end + +.channel env_frog_croak_leave +ldlayer 0, layer_2F4E +end + +.layer layer_2F4E +instr FONT00_INSTR_ANIMALS_0 +transpose 48 +notedv PITCH_F3, 0x8, 85 +notedv PITCH_D3, 0x8, 85 +portamento 0x81, 27, 127 +notedv PITCH_A3, 0x18, 85 +end + +.channel env_frog_croak_grow +ldlayer 0, layer_2F64 +end + +.layer layer_2F64 +instr FONT00_INSTR_ANIMALS_0 +transpose 48 +notedv PITCH_F3, 0x8, 85 +notedv PITCH_A3, 0x8, 85 +portamento 0x81, 34, 127 +notedv PITCH_C3, 0x18, 85 +end + +.channel env_cow_moo_distant +instr FONT00_INSTR_FIRE_COW +releaserate 180 +ldi 20 +stio 1 +.channel chan_2F7D +ldlayer 0, layer_2FB2 +ldi 255 +call delay_varyingvol +rand 2 +stseq 47, layer_2FAB+1 +randptr 106, 150 +stptrtoseq addr_2FB6 +ldi 1 +ldseq addr_2FB6 +stseq 0, chan_2F9F+1 +ldlayer 0, layer_2FAB +.channel chan_2F9F +ldi 1 +call delay_varyingvol +ldi 255 +call delay_varyingvol +rjump chan_2F7D + +.layer layer_2FAB +transpose 48 +notedv PITCH_C4, 0x93, 60 +end + +.layer layer_2FB2 +ldelay 0x7D00 +end + +.array addr_2FB6 +byte 0x0 +byte 0x0 + +.channel env_door_ranch_close +ldlayer 0, layer_2FBF +ldlayer 1, layer_2BC7 +end + +.layer layer_2FBF +instr FONT00_INSTR_SWORD_STRIKE +notedv PITCH_E2, 0x0, 84 +end + +.channel env_butterfly_transform +ldlayer 0, layer_2FCC +ldlayer 1, layer_2FDC +end + +.layer layer_2FCC +instr FONT00_INSTR_SHIMMER +transpose 48 +env envelope_6638, 251 +portamento 0x81, 39, 255 +notedv PITCH_C5, 0x64, 80 +end + +.layer layer_2FDC +instr FONT00_INSTR_FAIRY_MAGIC +env envelope_6638, 251 +portamento 0x81, 39, 255 +notedv PITCH_C5, 0x64, 80 +end + +.channel env_gossip_stretch +ldlayer 0, layer_2FEE +end + +.layer layer_2FEE +instr FONTANY_INSTR_BELL +env envelope_6610, 251 +portamento 0x83, 0, 255 +notedv PITCH_AF3, 0x3C, 60 +end + +.channel env_gossip_launch +ldlayer 0, layer_1F03 +jump chan_1A2C + +.channel env_spike_log_roll +ldlayer 0, layer_3006 +end + +.layer layer_3006 +instr FONT00_INSTR_CHAIN_RETRACT +legato +.layer layer_3009 +notedv PITCH_DF3, 32700, 80 +rjump layer_3009 + +.channel env_barrier_energy +ldlayer 0, layer_3016 +ldlayer 1, layer_3029 +end + +.layer layer_3016 +instr FONT00_INSTR_OCARINA_0 +env envelope_6674, 251 +legato +portamento 0x85, 15, 255 +.layer layer_3021 +notedv PITCH_C3, 0x64, 55 +notedv PITCH_C2, 0x64, 55 +rjump layer_3021 + +.layer layer_3029 +instr FONT00_INSTR_WARP +env envelope_6674, 251 +legato +portamento 0x85, 27, 255 +.layer layer_3034 +notedv PITCH_C4, 0x32, 65 +notedv PITCH_C3, 0x32, 65 +rjump layer_3034 + +.channel env_barrier_hum +ldlayer 0, layer_3046 +ldlayer 1, layer_3059 +ldlayer 2, layer_306C +end + +.layer layer_3046 +instr FONTANY_INSTR_SINE +env envelope_6674, 251 +legato +portamento 0x85, 3, 255 +.layer layer_3051 +notedv PITCH_G1, 0x2D, 40 +notedv PITCH_C1, 0x2D, 40 +rjump layer_3051 + +.layer layer_3059 +instr FONT00_INSTR_WARP +env envelope_6674, 251 +legato +portamento 0x85, 34, 255 +.layer layer_3064 +notedv PITCH_G4, 0x5A, 65 +notedv PITCH_G3, 0x5A, 65 +rjump layer_3064 + +.layer layer_306C +instr FONT00_INSTR_OCARINA_0 +env envelope_6674, 251 +legato +portamento 0x85, 7, 255 +.layer layer_3077 +notedv PITCH_E2, 0xB4, 55 +notedv PITCH_E1, 0xB4, 55 +rjump layer_3077 + +.channel env_child_walk +ldlayer 0, layer_3085 +end + +.layer layer_3085 +instr FONT00_INSTR_STEP_GROUND +portamento 0x81, 43, 255 +notedv PITCH_E2, 0xE, 60 +end + +.channel env_guard_walk +ldlayer 0, layer_30A0 +ldlayer 1, layer_3096 +end + +.layer layer_3096 +instr FONT00_INSTR_STEP_GROUND +portamento 0x81, 32, 127 +notedv PITCH_F3, 0xA, 76 +end + +.layer layer_30A0 +instr FONT00_INSTR_SWORD_STRIKE +notedv PITCH_F4, 0x6, 48 +instr FONT00_INSTR_STEP_FIRE +notedv PITCH_C4, 0xA, 48 +end + +.channel env_pillar_stop +ldlayer 0, layer_30AF +end + +.layer layer_30AF +instr FONT00_INSTR_BLOCK_LOCK +releaserate 241 +notedv PITCH_GF4, 0x6, 75 +notedv PITCH_F3, 0x64, 75 +end + +.filter filter_env0 +filter 0, 0, 0, 0, 0, 0, 0, 0 + +.filter filter_env1 +filter 0, 0, 0, 0, 0, 0, 0, 0 + +.filter filter_env2 +filter 0, 0, 0, 0, 0, 0, 0, 0 diff --git a/assets/sequences/sfxbanks/item.seq.inc b/assets/sequences/sfxbanks/item.seq.inc new file mode 100644 index 00000000000..c4fe4f97129 --- /dev/null +++ b/assets/sequences/sfxbanks/item.seq.inc @@ -0,0 +1,1201 @@ +.table table_item +entry item_map_select_cursor +entry item_sword_swing +entry item_sword_sheathe +entry item_sword_draw +entry item_arrow_shoot +entry item_boomerang_throw +entry item_shield_strike +entry item_bow_draw +entry item_shield_blade_bounce +entry item_arrow_strike +entry item_hammer_strike +entry item_hookshot_extend +entry item_mirror_fire +entry item_bomb_fuse +entry item_bomb_explode +entry item_bomb_defuse +entry item_boomerang_fly +entry item_sword_strike +entry item_hammer_swing +entry item_hookshot_strike +entry item_arrow_hit_enemy +entry item_arrow_hit_object +entry item_unused1 +entry item_unused2 +entry item_fishing_rod +entry env_bomb_rebound +entry item_sword_strike_wall +entry item_sword_strike_bwall +entry item_sword_strike_stone +entry item_stick_break +entry item_whip_epona +entry item_shield +entry item_slingshot_fly +entry item_slingshot_draw +entry item_sword_charge +entry item_sword_spin +entry item_sword_strike_unused +entry item_slingshot_reflect +entry item_shield_sheathe +entry item_hookshot_ready +entry item_hookshot_unused +entry item_hookshot_strike_object +entry item_sword_reflect +entry item_deku_nut_strike +entry item_jabu_struck +entry item_sword_unused +entry item_sword_spin_small +entry item_sword_spin_large +entry item_bow_empty +entry item_bombchu_fuse +entry item_shield_charge_1 +entry item_shield_charge_2 +entry item_shield_charge_3 +entry item_slingshot_empty +entry item_sword_unused2 +entry item_sword_strike_wood +entry item_shield_unused +entry item_arrow_magic_fly +entry item_arrow_fire_strike +entry item_arrow_ice_strike +entry item_arrow_light_strike +entry item_reel_slow +entry item_reel_fast +entry item_bow_draw +entry item_goddess_zoom +entry item_goddess_launch +entry item_goddess_boom +entry item_explosion_unused +entry env_horse_neigh +entry item_explosion_unused +entry item_explosive_flames +entry item_scarecrow_jump +entry item_flame_wall +entry env_triforce_glow +entry item_fishing_rod_strike +entry item_explosion_unused2 +entry item_sword_break +entry item_unused4 +entry item_sword_swing_magic +entry item_bomb_defuse + +.channel item_map_select_cursor +instr FONT00_INSTR_SWORD_STRIKE +ldlayer 0, layer_F89 +end + +.layer layer_F89 +notedv PITCH_F4, 0x18, 110 +end + +.channel item_sword_swing +ldlayer 0, layer_F91 +end + +.layer layer_F91 +instr FONT00_INSTR_SWORD_MISS +portamento 0x81, 29, 255 +notedv PITCH_D2, 0x2A, 100 +end + +.channel item_sword_sheathe +instr FONT00_INSTR_SWORD_SHEATHE +ldlayer 0, layer_FA1 +end + +.layer layer_FA1 +notedv PITCH_A3, 0x30, 100 +end + +.channel item_sword_draw +instr FONT00_INSTR_SWORD_DRAW +ldlayer 0, layer_FAB +end + +.layer layer_FAB +notedv PITCH_A3, 0x30, 100 +end + +.channel item_arrow_shoot +ldlayer 0, layer_FB3 +end + +.layer layer_FB3 +instr FONT00_INSTR_SWORD_SWING +notedv PITCH_A3, 0x30, 100 +end + +.channel item_boomerang_throw +instr FONT00_INSTR_WHISTLE_AIR +ldlayer 0, layer_FBF +end + +.layer layer_FBF +legato +portamento 0x85, 0, 255 +notedv PITCH_A3, 0xC, 80 +notedv PITCH_F2, 0x19, 80 +end + +.channel item_shield_strike +instr FONT00_INSTR_SWORD_HIT_SHIELD +env envelope_664C +ldlayer 0, layer_FD4 +end + +.layer layer_FD4 +notedv PITCH_B3, 0x6, 82 +notedv PITCH_E3, 0x0, 82 +end + +.channel item_bow_draw +instr FONT00_INSTR_BOW +ldlayer 0, layer_FE1 +end + +.layer layer_FE1 +portamento 0x81, 43, 255 +notedv PITCH_GF4, 0xE, 110 +end + +.channel item_shield_blade_bounce +instr FONT00_INSTR_SWORD_HIT_SHIELD +env envelope_65E8 +ldlayer 0, layer_FF5 +ldlayer 1, layer_FF9 +end + +.layer layer_FF5 +notedv PITCH_C4, 0x24, 105 +end + +.layer layer_FF9 +instr FONT00_INSTR_SWORD_STRIKE +transpose 48 +notedv PITCH_DF3, 0x0, 100 +end + +.channel item_arrow_strike +instr FONT00_INSTR_ARROW_WOOD +ldlayer 0, layer_1007 +end + +.layer layer_1007 +notedv PITCH_C4, 0x45, 100 +end + +.channel item_hammer_strike +gain 20 +ldlayer 0, layer_1011 +end + +.layer layer_1011 +instr FONT00_INSTR_SWORD_STRIKE +releaserate 236 +notedv PITCH_DF1, 0x6, 76 +instr FONT00_INSTR_SLAM_HEAVY +env envelope_65E8, 240 +notedv PITCH_B3, 0x24, 110 +end + +.channel item_hookshot_extend +ldlayer 0, layer_1033 +ldlayer 1, layer_1029 +end + +.layer layer_1029 +instr FONT00_INSTR_EXPLOSION_0 +env envelope_664C, 255 +notedv PITCH_B5, 0xC, 108 +end + +.layer layer_1033 +instr FONT00_INSTR_CHAIN +.layer layer_1035 +notedv PITCH_B4, 0x7, 93 +rjump layer_1035 + +.channel item_mirror_fire +gain 15 +ldlayer 0, layer_1045 +ldlayer 1, layer_105C +end + +.layer layer_1043 +transpose -9 + +.layer layer_1045 +instr FONT00_INSTR_SWORD_HIT_SHIELD +env envelope_65E8, 251 +portamento 0x81, 16, 100 +notedv PITCH_F4, 0x6, 102 +portamento 0x81, 20, 100 +notedv PITCH_E5, 0x28, 110 +end + +.layer layer_105A +transpose -9 + +.layer layer_105C +instr FONT00_INSTR_SYNTH_BUZZ +env envelope_6610, 251 +portamento 0x81, 32, 208 +notedv PITCH_B5, 0x28, 80 +end + +.channel item_bomb_fuse +instr FONT00_INSTR_BOMB +ldlayer 0, layer_1070 +end + +.layer layer_1070 +legato +.layer layer_1071 +notedv PITCH_A3, 0x30, 80 +rjump layer_1071 + +.channel item_bomb_explode +ldlayer 0, layer_107A +end + +.layer layer_107A +instr FONT00_INSTR_EXPLOSION_0 +env envelope_66D0, 225 +notedv PITCH_F4, 0xA0, 110 +end + +.channel item_bomb_defuse +ldlayer 0, layer_1089 +end + +.layer layer_1089 +instr FONT00_INSTR_BOMB +env envelope_65E8, 245 +portamento 0x85, 34, 255 +notedv PITCH_E4, 0x8, 105 +notedv PITCH_F3, 0x18, 105 +end + +.layer layer_unused_109A +portamento 0x81, 32, 255 +notedv PITCH_F2, 0x1E, 105 +end + +.channel item_boomerang_fly +instr FONT00_INSTR_SWORD_SWING +env envelope_6688 +ldlayer 0, layer_10AB +end + +.layer layer_10AB +legato +portamento 0x85, 8, 255 +notedv PITCH_F2, 0x18, 90 +notedv PITCH_B3, 0xE, 90 +nolegato +legato +portamento 0x85, 10, 255 +notedv PITCH_G2, 0x14, 90 +notedv PITCH_C4, 0xC, 90 +nolegato +.layer layer_10C3 +legato +portamento 0x85, 12, 255 +notedv PITCH_A2, 0x11, 90 +notedv PITCH_D4, 0xA, 90 +nolegato +jump layer_10C3 + +.channel item_sword_strike +instr FONT00_INSTR_SOFT_HIT +env envelope_66C8 +ldlayer 0, layer_10DB +end + +.layer layer_10DB +notedv PITCH_GF2, 0x3, 110 +portamento 0x2, 11, 12 +notedv PITCH_AF3, 0x6, 110 +end + +.channel item_hammer_swing +ldlayer 0, layer_10EA +end + +.layer layer_10EA +instr FONT00_INSTR_SWORD_MISS +portamento 0x81, 19, 255 +notedv PITCH_E1, 0x60, 100 +end + +.channel item_hookshot_strike +ldlayer 0, layer_10F8 +end + +.layer layer_10F8 +call layer_fn_1103 +portamento 0x1, 34, 24 +notedv PITCH_D4, 0x48, 100 +end + +.layer layer_fn_1103 +instr FONT00_INSTR_SWORD_STRIKE +transpose -18 +notedv PITCH_E3, 0x9, 100 +end + +.channel item_arrow_hit_enemy +instr FONT00_INSTR_SWORD_SWING +ldlayer 0, layer_1111 +end + +.layer layer_1111 +portamento 0x81, 38, 127 +notedv PITCH_E1, 0x14, 105 +portamento 0x81, 3, 127 +notedv PITCH_F3, 0xA, 105 +end + +.channel item_arrow_hit_object +jump item_arrow_strike + +.channel item_unused1 +ldlayer 0, layer_112A +ldlayer 1, layer_113A +end + +.layer layer_112A +transpose -2 +instr FONT00_INSTR_SWORD_SWING +legato +portamento 0x85, 3, 255 +notedv PITCH_C2, 0x9, 90 +notedv PITCH_BF3, 0x12, 90 +end + +.layer layer_113A +transpose -1 +instr FONT00_INSTR_EGG_BREAK +portamento 0x81, 34, 255 +notedv PITCH_C3, 0x1B, 80 +end + +.channel item_unused2 +ldlayer 0, layer_114D +ldlayer 1, layer_115D +end + +.layer layer_114D +transpose 4 +instr FONT00_INSTR_SWORD_SWING +legato +portamento 0x85, 3, 255 +notedv PITCH_F2, 0xC, 103 +notedv PITCH_F4, 0x18, 103 +end + +.layer layer_115D +transpose 4 +instr FONT00_INSTR_EGG_BREAK +portamento 0x81, 34, 255 +notedv PITCH_C3, 0x28, 87 +end + +.channel item_fishing_rod +ldlayer 0, layer_1170 +ldlayer 1, layer_117C +end + +.layer layer_1170 +instr FONT00_INSTR_SWORD_MISS +portamento 0x81, 32, 255 +notedv PITCH_F2, 0x24, 105 +ldelay 0x68 +end + +.layer layer_117C +instr FONT00_INSTR_WHOOSH +portamento 0x81, 46, 44 +notedv PITCH_G3, 0x8C, 75 +end + +.channel item_sword_strike_wall +instr FONT00_INSTR_SWORD_STRIKE +env envelope_6674 +ldlayer 0, layer_1196 +.channel chan_118F +vibfreq 127 +vibdepthgrad 0, 128, 56 +end + +.layer layer_1196 +notedv PITCH_E2, 0x60, 110 +end + +.channel item_sword_strike_bwall +instr FONT00_INSTR_SWORD_STRIKE +ldlayer 0, layer_11A3 +ldlayer 1, layer_11AF +end + +.layer layer_11A3 +env envelope_6674, 251 +portamento 0x1, 27, 30 +notedv PITCH_A3, 0x60, 100 +end + +.layer layer_11AF +notedv PITCH_C3, 0x60, 96 +end + +.channel item_sword_strike_stone +ldlayer 0, layer_11B7 +end + +.layer layer_11B7 +instr FONT00_INSTR_SWORD_STRIKE +env envelope_6610, 251 +notedv PITCH_A1, 0x8, 110 +notedv PITCH_F1, 0x30, 110 +end + +.channel item_stick_break +instr FONT00_INSTR_WOOD_BREAK +env envelope_6660 +ldlayer 0, layer_11CD +end + +.layer layer_11CD +notedvg PITCH_AF2, 0x7, 93, 127 +notedv PITCH_G3, 0x5, 90 +end + +.channel item_whip_epona +ldlayer 0, layer_11D9 +end + +.layer layer_11D9 +instr FONT00_INSTR_SWORD_SWING +notedv PITCH_A3, 0x8, 105 +instr FONT00_INSTR_WHIP_CORK +env envelope_6624, 255 +notedv PITCH_GF3, 0x16, 87 +end + +.channel item_shield +ldlayer 0, layer_11EF +ldlayer 1, layer_11F5 +end + +.layer layer_11EF +instr FONT00_INSTR_SWORD_SHEATHE +notedv PITCH_F3, 0x12, 110 +end + +.layer layer_11F5 +instr FONT00_INSTR_SWORD_STRIKE +transpose 48 +env envelope_6720, 251 +notedv PITCH_C3, 0xA, 75 +notedvg PITCH_E3, 0x4, 75, 127 +notedv PITCH_E3, 0x4, 75 +end + +.channel item_slingshot_fly +instr FONT00_INSTR_SWORD_SWING +ldlayer 0, layer_120E +end + +.layer layer_120E +portamento 0x81, 48, 255 +notedv PITCH_A0, 0x12, 100 +end + +.channel item_slingshot_draw +instr FONT00_INSTR_BOW +ldlayer 0, layer_121C +end + +.layer layer_121C +portamento 0x81, 39, 127 +notedv PITCH_B4, 0x7, 110 +end + +.channel item_sword_charge +ldi 24 +stio 1 +ldlayer 0, layer_124B +ldlayer 1, layer_1234 +vibfreq 127 +vibdepthgrad 0, 160, 9 +end + +.layer layer_1234 +instr FONTANY_INSTR_8PULSE +portamento 0x81, 3, 255 +notedv PITCH_G4, 0x64, 30 +portamento 0x81, 15, 255 +notedv PITCH_G5, 0x64, 30 +legato +.layer layer_1245 +notedv PITCH_G5, 0xC8, 30 +rjump layer_1245 + +.layer layer_124B +instr FONT00_INSTR_SYNTH_BUZZ +legato +transpose 9 +portamento 0x81, 3, 255 +.layer layer_1254 +notedv PITCH_G5, 0xC8, 50 +rjump layer_1254 + +.channel item_sword_spin +ldlayer 0, layer_1266 +ldlayer 1, layer_1264 +ldlayer 2, layer_1170 +end + +.layer layer_1264 +transpose -4 + +.layer layer_1266 +instr FONT00_INSTR_WHOOSH +portamento 0x81, 51, 44 +notedv PITCH_F3, 0x8C, 90 +end + +.channel item_sword_strike_unused +instr FONT00_INSTR_SOFT_HIT +env envelope_66C8 +ldlayer 0, layer_127D +ldlayer 1, layer_113A +end + +.layer layer_127D +notedv PITCH_A2, 0x3, 110 +portamento 0x2, 14, 12 +notedv PITCH_B3, 0x6, 110 +ldelay 0x7 +end + +.channel item_slingshot_reflect +ldlayer 0, layer_128E +end + +.layer layer_128E +instr FONT00_INSTR_SWORD_STRIKE +transpose 48 +notedvg PITCH_A2, 0x3, 100, 127 +releaserate 251 +portamento 0x81, 15, 48 +notedv PITCH_DF3, 0x24, 100 +end + +.channel item_shield_sheathe +ldlayer 0, layer_12A7 +ldlayer 1, layer_12AD +end + +.layer layer_12A7 +instr FONT00_INSTR_SWORD_SHEATHE +notedv PITCH_A3, 0x12, 110 +end + +.layer layer_12AD +instr FONT00_INSTR_SWORD_STRIKE +transpose 48 +env envelope_6720, 251 +notedv PITCH_F3, 0xA, 75 +notedvg PITCH_E3, 0x4, 75, 127 +notedv PITCH_E2, 0x4, 75 +end + +.channel item_hookshot_ready +ldlayer 0, layer_12C7 +ldlayer 1, layer_12CD +end + +.layer layer_12C7 +instr FONT00_INSTR_SWORD_SHEATHE +notedv PITCH_EF4, 0x10, 105 +end + +.layer layer_12CD +instr FONT00_INSTR_SWORD_STRIKE +env envelope_664C, 251 +notedv PITCH_AF3, 0x4, 86 +notedv PITCH_A2, 0x4, 64 +end + +.channel item_hookshot_unused +ldlayer 0, layer_12E7 +ldlayer 1, layer_12E1 +end + +.layer layer_12E1 +instr FONT00_INSTR_SWORD_SHEATHE +notedv PITCH_A2, 0x28, 105 +end + +.layer layer_12E7 +instr FONT00_INSTR_CHAIN +releaserate 238 +notedv PITCH_D5, 0x8, 86 +instr 26 +notedv PITCH_GF4, 0x18, 100 +end + +.channel item_hookshot_strike_object +ldlayer 0, layer_12FB +ldlayer 1, layer_1309 +end + +.layer layer_12FB +instr FONT00_INSTR_EXPLOSION_0 +env envelope_6624, 251 +portamento 0x81, 50, 144 +notedv PITCH_B2, 0x20, 110 +end + +.layer layer_1309 +instr FONT00_INSTR_SWORD_STRIKE +env envelope_664C, 241 +notedv PITCH_AF2, 0x4, 64 +notedv PITCH_A3, 0xC, 56 +end + +.channel item_sword_reflect +ldi 24 +stio 1 +ldlayer 0, layer_1320 +ldlayer 1, layer_117C +end + +.layer layer_1320 +instr FONT00_INSTR_SYNTH_BUZZ +legato +transpose 12 +portamento 0x81, 56, 127 +notedv PITCH_F4, 0x24, 80 +end + +.channel item_deku_nut_strike +ldlayer 0, layer_1334 +ldlayer 1, layer_1344 +end + +.layer layer_1334 +instr FONT00_INSTR_SWORD_STRIKE +transpose 48 +env envelope_66D0, 232 +portamento 0x81, 19, 72 +notedv PITCH_GF2, 0x4, 83 +end + +.layer layer_1344 +instr FONT00_INSTR_WHIP_CORK +releaserate 225 +portamento 0x81, 45, 200 +notedv PITCH_DF3, 0x4, 110 +end + +.channel item_jabu_struck +ldi 32 +stio 1 +ldlayer 0, layer_137F +ldlayer 1, layer_1373 +ldlayer 2, layer_1361 +.channel chan_135C +vibfreq 100 +vibdepth 84 +end + +.layer layer_1361 +legato +instr FONT00_INSTR_OCARINA_0 +env envelope_6674, 251 +portamento 0x85, 11, 255 +notedv PITCH_AF2, 0x24, 60 +notedv PITCH_AF1, 0x24, 60 +end + +.layer layer_1373 +instr FONT00_INSTR_EGG_BREAK +portamento 0x82, 15, 255 +notedv PITCH_C3, 0x3E, 105 +end + +.layer layer_137D +transpose -6 + +.layer layer_137F +ldelay 0x1 +instr FONT00_INSTR_ROAR_BARK +env envelope_65D8, 251 +portamento 0x81, 20, 255 +notedv PITCH_AF2, 0x8, 85 +portamento 0x81, 27, 255 +notedv PITCH_C2, 0x60, 85 +end + +.channel item_sword_unused +instr FONT00_INSTR_SWORD_DRAW +ldlayer 0, layer_139C +end + +.layer layer_139C +portamento 0x83, 32, 127 +notedv PITCH_G3, 0x8, 100 +notedv PITCH_EF4, 0x18, 100 +end + +.channel item_sword_spin_small +ldlayer 0, layer_13C5 +ldlayer 1, layer_13B1 +ldlayer 2, layer_1170 +end + +.layer layer_13B1 +transpose 17 +.layer layer_13B3 +instr FONT00_INSTR_SYNTH_BUZZ +env envelope_6638, 251 +legato +portamento 0x85, 44, 255 +notedv PITCH_F5, 0x10, 68 +notedv PITCH_D1, 0x2C, 68 +end + +.layer layer_13C5 +transpose -2 +jump layer_1266 + +.channel item_sword_spin_large +ldlayer 0, layer_1266 +ldlayer 1, layer_13D4 +ldlayer 2, layer_13D8 +end + +.layer layer_13D4 +transpose 20 +rjump layer_13B3 + +.layer layer_13D8 +instr FONT00_INSTR_FLAME_THUNDER +releaserate 221 +legato +portamento 0x85, 28, 255 +notedv PITCH_DF4, 0x10, 74 +notedv PITCH_A3, 0x44, 74 +end + +.channel item_bow_empty +gain 22 +ldlayer 0, layer_13EE +end + +.layer layer_13EE +instr FONT00_INSTR_BOW +env envelope_65D8, 251 +transpose 48 +portamento 0x81, 43, 127 +notedv PITCH_AF4, 0x60, 95 +end + +.channel item_bombchu_fuse +ldlayer 0, layer_1402 +end + +.layer layer_1402 +instr FONT00_INSTR_BOMB +transpose 48 +legato +portamento 0x1, 36, 56 +.layer layer_140B +notedv PITCH_E4, 0x7D00, 80 +rjump layer_140B + +.channel item_shield_charge_1 +ldi 0 +stio 6 +.channel chan_1414 +ldseq addr_142D +stseq 0, layer_fn_145A+1 +ldio 6 +ldseq addr_1431 +stseq 0, layer_1455+1 +ldi 24 +stio 1 +ldlayer 0, layer_1448 +ldlayer 1, layer_1435 +end + +.array addr_142D +byte 0x0 +byte 0x4 +byte 0x8 +byte 0x0 + +.array addr_1431 +byte 0x60 +byte 0x30 +byte 0x18 +byte 0x60 + +.layer layer_1435 +call layer_fn_145A + +.layer layer_1438 +instr FONT00_INSTR_SYNTH +legato +portamento 0x85, 24, 255 +notedv PITCH_C2, 0x6, 90 +notedv PITCH_B4, 0x50, 90 +ldelay 0x21 +end + +.layer layer_1448 +call layer_fn_145A +instr FONT00_INSTR_SYNTH +env envelope_66C8, 251 +.layer layer_1451 +portamento 0x81, 3, 255 +.layer layer_1455 +notedv PITCH_A2, 0x60, 88 +rjump layer_1451 + +.layer layer_fn_145A +transpose 0 +end + +.channel item_shield_charge_2 +ldi 1 +stio 6 +rjump chan_1414 + +.channel item_shield_charge_3 +ldi 2 +stio 6 +rjump chan_1414 + +.channel item_slingshot_empty +instr FONT00_INSTR_BOW +env envelope_67BC +gain 8 +ldlayer 0, layer_1472 +end + +.layer layer_1472 +transpose 48 +portamento 0x81, 48, 127 +notedv PITCH_DF5, 0x30, 105 +end + +.channel item_sword_unused2 +ldlayer 0, layer_1483 +ldlayer 1, layer_148D +end + +.layer layer_1483 +instr FONT00_INSTR_EXPLOSION_0 +portamento 0x81, 48, 144 +notedv PITCH_F2, 0xE, 96 +end + +.layer layer_148D +instr FONT00_INSTR_SWORD_STRIKE +notedv PITCH_BF2, 0xE, 72 +end + +.channel item_sword_strike_wood +ldlayer 0, layer_149A +ldlayer 1, layer_14A4 +end + +.layer layer_149A +instr FONT00_INSTR_STICK_ATTACK +env envelope_65E8, 244 +notedv PITCH_GF4, 0x8, 110 +end + +.layer layer_14A4 +instr FONT00_INSTR_STEP_BRIDGE +ldelay 0x3 +env envelope_65E8, 244 +notedv PITCH_GF2, 0x5, 110 +end + +.channel item_shield_unused +gain 15 +ldlayer 0, layer_1043 +ldlayer 1, layer_105A +end + +.channel item_arrow_magic_fly +ldlayer 0, layer_14C0 +ldlayer 1, layer_FB3 +end + +.layer layer_14C0 +instr FONT00_INSTR_WHOOSH +portamento 0x81, 15, 40 +notedv PITCH_F4, 0x40, 80 +end + +.channel item_arrow_fire_strike +ldlayer 0, layer_14D6 +.channel chan_14CD +ldlayer 1, layer_14E0 +ldlayer 2, layer_15B1 +gain 20 +end + +.layer layer_14D6 +instr FONT00_INSTR_IGNITE +env envelope_6688, 200 +notedv PITCH_C3, 0x44, 100 +end + +.layer layer_14E0 +transpose 48 +jump layer_2A06 + +.channel item_arrow_ice_strike +ldlayer 0, layer_14EA +rjump chan_14CD + +.layer layer_14EA +instr FONT00_INSTR_WARP +transpose 10 +env envelope_6688, 200 +notedv PITCH_C5, 0x44, 100 +end + +.channel item_arrow_light_strike +ldlayer 0, layer_14FB +rjump chan_14CD + +.layer layer_14FB +instr FONT00_INSTR_FAIRY +env envelope_667C, 200 +notedv PITCH_A4, 0x44, 54 +end + +.channel item_reel_slow +instr FONT00_INSTR_BOW +ldlayer 0, layer_150B +end + +.layer layer_150B +notedv PITCH_F4, 0x6, 102 +rjump layer_150B + +.channel item_reel_fast +instr FONT00_INSTR_BOW +ldlayer 0, layer_1516 +end + +.layer layer_1516 +notedv PITCH_A4, 0x3, 102 +rjump layer_1516 + +.channel item_goddess_zoom +call chan_fn_2823 +ldlayer 0, layer_1528 +ldlayer 1, layer_1532 +ldlayer 2, layer_153C +end + +.layer layer_1528 +instr FONT00_INSTR_SHIMMER +portamento 0x81, 55, 255 +notedv PITCH_E3, 0x48, 65 +end + +.layer layer_1532 +instr FONT00_INSTR_MECH_CHARGE +portamento 0x81, 55, 231 +notedv PITCH_E4, 0x48, 58 +end + +.layer layer_153C +instr FONT00_INSTR_EXPLOSION_0 +env envelope_66D0, 231 +portamento 0x81, 51, 255 +notedv PITCH_A2, 0x30, 72 +end + +.channel item_goddess_launch +call chan_fn_2823 +ldlayer 0, layer_1557 +ldlayer 1, layer_1561 +ldlayer 2, layer_156F +end + +.layer layer_1557 +instr FONT00_INSTR_SHIMMER +portamento 0x82, 44, 231 +notedv PITCH_E2, 0x48, 85 +end + +.layer layer_1561 +instr FONT00_INSTR_MECH_CHARGE +env envelope_66F4, 231 +portamento 0x82, 51, 255 +notedv PITCH_D4, 0x48, 112 +end + +.layer layer_156F +instr FONT00_INSTR_EXPLOSION_0 +env envelope_66D0, 231 +portamento 0x82, 51, 255 +notedv PITCH_A2, 0x30, 85 +end + +.channel item_goddess_boom +ldi 30 +stio 1 +ldlayer 0, layer_158A +ldlayer 1, layer_15A2 +ldlayer 2, layer_15B1 +end + +.layer layer_158A +instr FONT00_INSTR_SHIMMER +portamento 0x81, 48, 231 +notedv PITCH_A2, 0x18, 75 +instr 77 +env envelope_6740, 231 +portamento 0x81, 38, 255 +notedv PITCH_B2, 0xE8, 105 +end + +.layer layer_15A2 +instr FONT00_INSTR_DISTORTION +env envelope_67CC, 231 +portamento 0x81, 14, 255 +notedv PITCH_B2, 0xE8, 95 +end + +.layer layer_15B1 +instr FONT00_INSTR_EXPLOSION_0 +env envelope_6610, 231 +notedv PITCH_A3, 0x48, 105 +end + +.channel item_explosion_unused +ldlayer 0, layer_15C7 +ldlayer 1, layer_15C5 +ldlayer 2, layer_2185 +end + +.layer layer_15C5 +transpose -18 + +.layer layer_15C7 +instr FONT00_INSTR_EXPLOSION_0 +releaserate 221 +notedv PITCH_B4, 0xC8, 85 +end + +.channel item_explosive_flames +ldlayer 0, layer_15D7 +ldlayer 1, layer_1EF0 +end + +.layer layer_15D7 +instr FONT00_INSTR_EXPLOSION_0 +releaserate 240 +notedv PITCH_B4, 0x7F, 85 +end + +.channel item_scarecrow_jump +ldlayer 0, layer_15E3 +end + +.layer layer_15E3 +instr FONT00_INSTR_BOW +env envelope_65D8, 251 +transpose 48 +portamento 0x81, 19, 255 +notedv PITCH_AF4, 0x30, 80 +end + +.channel item_flame_wall +ldlayer 0, layer_2C60 +ldlayer 1, layer_1BEF +end + +.channel item_fishing_rod_strike +ldlayer 0, layer_1601 +ldlayer 1, layer_160C +end + +.layer layer_1601 +instr FONT00_INSTR_WHIP_CORK +releaserate 224 +notedv PITCH_G4, 0x6, 100 +notedv PITCH_AF3, 0x0, 100 +end + +.layer layer_160C +instr FONT00_INSTR_WHOOSH +notedv PITCH_EF4, 0x14, 76 +instr 33 +notedv PITCH_EF5, 0xA, 102 +end + +.channel item_explosion_unused2 +instr FONT00_INSTR_EXPLOSION_0 +env envelope_66D0 +ldlayer 0, layer_1620 +end + +.layer layer_1620 +notedv PITCH_G3, 0x0, 95 +end + +.channel item_sword_break +instr FONT00_INSTR_SWORD_HIT_SHIELD +env envelope_6610 +ldlayer 0, layer_1633 +ldlayer 1, layer_105A +ldlayer 2, layer_11B7 +end + +.layer layer_1633 +instr FONT00_INSTR_SWORD_STRIKE +transpose 36 +notedv PITCH_E3, 0x8, 100 +notedv PITCH_A3, 0x0, 100 +end + +.channel item_unused4 +ldlayer 0, layer_1642 +end + +.layer layer_1642 +instr FONT00_INSTR_WHIP_CORK +notedv PITCH_G3, 0xD, 96 +end + +.channel item_sword_swing_magic +ldi 16 +stio 1 +ldlayer 1, layer_1651 +jump item_hammer_swing + +.layer layer_1651 +instr FONT00_INSTR_SHIMMER +env envelope_6610, 235 +portamento 0x82, 29, 127 +notedv PITCH_GF2, 0x28, 74 +end + +.filter filter_item0 +filter 0, 0, 0, 0, 0, 0, 0, 0 + +.filter filter_item1 +filter 0, 0, 0, 0, 0, 0, 0, 0 diff --git a/assets/sequences/sfxbanks/ocarina.seq.inc b/assets/sequences/sfxbanks/ocarina.seq.inc new file mode 100644 index 00000000000..19c199484fc --- /dev/null +++ b/assets/sequences/sfxbanks/ocarina.seq.inc @@ -0,0 +1,121 @@ +.table table_ocarina +entry ocarina_ocarina +entry ocarina_voidout +entry env_door_open_oca +entry ocarina_warp_in +entry ocarina_warp_out +entry env_grotto_exit +entry ocarina_respawn +entry ocarina_ocarina + +.channel ocarina_ocarina +ldi 80 +stio 1 +ldio 7 +and 7 +ldseq addr_5F30 +stseq 0, chan_5F0C+1 +ldio 7 +and 7 +ldseq addr_5F38 +stseq 0, layer_5F2B+3 +.channel chan_5F0C +instr FONT00_INSTR_OCARINA_0 +ldio 5 +rbltz chan_5F15 +stseq 0, layer_5F29+1 +.channel chan_5F15 +ldlayer 0, layer_5F28 +.channel chan_5F18 +ldio 6 +rbltz chan_5F21 +stseq 0, @+1 +vibdepth 0 +.channel chan_5F21 +ldi 1 +call delay_varyingvol +rjump chan_5F18 + +.layer layer_5F28 +legato +.layer layer_5F29 +transpose 0 +.layer layer_5F2B +notedv PITCH_C4, 0x1E0, 127 +end + +.array addr_5F30 +byte 0x34 +byte 0x55 +byte 0x56 +byte 0x59 +byte 0x53 +byte 0x52 +byte 0x34 +byte 0x34 + +.array addr_5F38 +byte 115 +byte 115 +byte 100 +byte 115 +byte 100 +byte 115 +byte 115 +byte 115 + +.channel ocarina_warp_out +ldi 129 +.channel chan_5F42 +vibfreq 64 +vibdepthgrad 4, 8, 8 +stseq 0, layer_5F5C+1 +instr FONT00_INSTR_FAIRY +env envelope_66FC +releaserate 240 +ldlayer 0, layer_5F5A +ldlayer 1, layer_5F5C +end + +.layer layer_5F5A +transpose 24 + +.layer layer_5F5C +portamento 0x81, 15, 255 +notedv PITCH_G3, 0x8C, 80 +end + +.channel ocarina_warp_in +ldi 130 +rjump chan_5F42 + +.channel ocarina_voidout +ldi 80 +stseq 0, layer_5F90+1 +ldi 129 +.channel chan_5F71 +stseq 0, layer_5F8C+1 +ldi 20 +stio 1 +gain 15 +ldlayer 0, layer_5F84 +vibfreq 8 +vibdepthgrad 4, 40, 8 +end + +.layer layer_5F84 +instr FONT00_INSTR_SHIMMER +transpose 48 +env envelope_6740, 251 +.layer layer_5F8C +portamento 0x81, 32, 224 +.layer layer_5F90 +notedv PITCH_DF2, 0x50, 105 +ldelay 0x60 +end + +.channel ocarina_respawn +ldi 40 +stseq 0, layer_5F90+1 +ldi 130 +rjump chan_5F71 diff --git a/assets/sequences/sfxbanks/player.seq.inc b/assets/sequences/sfxbanks/player.seq.inc new file mode 100644 index 00000000000..8790ab3075b --- /dev/null +++ b/assets/sequences/sfxbanks/player.seq.inc @@ -0,0 +1,2304 @@ +.table table_player_kid +entry player_child_step_dirt +entry player_child_step_sand +entry player_child_step_stone +entry player_child_step_jabu +entry player_child_step_water +entry player_child_step_water_deep +entry player_child_step_tall_grass +entry player_child_step_lava +entry player_child_step_grass +entry player_child_step_carpet +entry player_child_step_wood +entry player_child_step_bridge +entry player_step_vines +entry player_step_iron_boots +entry player_step_unused +entry player_child_step_ice +entry player_child_jump_dirt +entry player_child_jump_sand +entry player_child_jump_stone +entry player_child_jump_jabu +entry player_child_jump_water +entry player_child_jump_water_deep +entry player_child_jump_tall_grass +entry player_child_jump_lava +entry player_child_jump_grass +entry player_child_jump_carpet +entry player_child_jump_wood +entry player_child_jump_bridge +entry player_child_step_dirt +entry player_jump_iron_boots +entry player_jump_unused +entry player_child_jump_ice +entry player_child_land_dirt +entry player_child_land_sand +entry player_child_land_stone +entry player_child_land_jabu +entry player_child_land_water +entry player_child_land_water_deep +entry player_child_land_tall_grass +entry player_child_land_lava +entry player_child_land_grass +entry player_child_land_carpet +entry player_child_land_wood +entry player_child_land_bridge +entry player_child_step_dirt +entry player_land_iron_boots +entry player_land_unused +entry player_child_land_ice +entry player_climb_down_vine_top +entry player_climb_up_vine_top +entry player_climb_on_epona +entry player_jump_off_epona +entry player_shield_epona +entry player_change_item_held +entry player_catch_boomerang +entry player_large_splash +entry player_small_splash +entry player_swim +entry player_throw +entry player_hit_wall_old +entry player_flip +entry player_sidejump +entry player_hit_blunt +entry player_hit_stab +entry player_slip_dirt +entry player_slip_sand +entry player_slip_stone +entry player_slip_jabu +entry player_slip_water +entry player_slip_water_deep +entry player_slip_tall_grass +entry player_slip_lava +entry player_slip_grass +entry player_slip_carpet +entry player_slip_wood +entry player_slip_bridge +entry player_child_step_water +entry player_slip_wood +entry player_slip_unused +entry player_slip_stone +entry player_rebound_dirt +entry player_rebound_sand +entry player_rebound_stone +entry player_rebound_jabu +entry player_rebound_water +entry player_rebound_water_deep +entry player_rebound_tall_grass +entry player_rebound_lava +entry player_rebound_grass +entry player_rebound_carpet +entry player_rebound_wood +entry player_rebound_bridge +entry player_child_step_dirt +entry player_rebound_wood +entry player_rebound_unused +entry player_rebound_ice +entry player_step_iron_boots +entry player_jump_iron_boots +entry player_land_iron_boots +entry player_dive_surface +entry player_dive_down +entry player_dive_move +entry player_child_metalequip +entry player_adult_metalequip +entry player_electric_shock +entry player_lift_grass +entry player_lift_rock +entry player_morpha_bubble +entry player_lift_giant_rock +entry player_sword_charge +entry player_freeze +entry player_lift_pot +entry player_hit_unused +entry player_idle_shuffle +entry player_idle_slide +entry player_dive_unused +entry player_freeze_short +entry player_ice_break +entry player_slip_ice +entry player_sheathe_item_unused +entry player_lift_crate +entry player_cast_fire +entry player_cast_wind +entry player_cast_wind_return +entry player_cast_soul +entry player_arrow_fire_charge +entry player_arrow_ice_charge +entry player_arrow_light_charge +.table table_player_old +entry player_adult_step_dirt +entry player_adult_step_sand +entry player_adult_step_stone +entry player_adult_step_jabu +entry player_adult_step_water +entry player_adult_step_water_deep +entry player_adult_step_tall_grass +entry player_adult_step_lava +entry player_adult_step_grass +entry player_adult_step_carpet +entry player_adult_step_wood +entry player_adult_step_bridge +entry player_adult_step_vine +entry player_step_iron_boots +entry player_child_step_dirt +entry player_adult_step_ice +entry player_adult_jump_dirt +entry player_adult_jump_sand +entry player_adult_jump_stone +entry player_adult_jump_jabu +entry player_adult_jump_water +entry player_adult_jump_water_deep +entry player_adult_jump_tall_grass +entry player_adult_jump_lava +entry player_adult_jump_grass +entry player_adult_jump_carpet +entry player_adult_jump_wood +entry player_adult_jump_bridge +entry player_child_step_dirt +entry player_jump_iron_boots +entry player_child_step_dirt +entry player_adult_jump_ice +entry player_adult_land_dirt +entry player_adult_land_sand +entry player_adult_land_stone +entry player_adult_land_jabu +entry player_adult_land_water +entry player_adult_land_water_deep +entry player_adult_land_tall_grass +entry player_adult_land_lava +entry player_adult_land_grass +entry player_adult_land_carpet +entry player_adult_land_wood +entry player_adult_land_bridge +entry player_adult_step_dirt +entry player_land_iron_boots +entry player_child_step_dirt +entry player_adult_land_ice +entry player_crawl_dirt +entry player_crawl_sand +entry player_crawl_stone +entry player_crawl_jabu +entry player_crawl_water +entry player_crawl_water_deep +entry player_crawl_tall_grass +entry player_crawl_lava +entry player_crawl_grass +entry player_crawl_carpet +entry player_crawl_wood +entry player_crawl_bridge +entry player_child_step_dirt +entry player_child_step_dirt +entry player_child_step_dirt +entry player_crawl_ice +entry player_cast_soul_end +entry player_roll_dust +entry player_crash_unused +entry player_cast_soul_appear +entry player_fairy_heal +entry player_rebound_unarmed +entry player_plant_seed +entry player_plant_grow +entry player_cast_wind_dismiss +entry player_hover +entry player_plant_hover +entry env_elevator_move +entry player_child_step_dirt +entry player_child_step_dirt +entry player_child_step_dirt +entry player_child_step_dirt +entry player_slip_dirt2 # Used; all other slip values are ignored +entry player_slip_sand2 +entry player_slip_stone2 +entry player_slip_jabu2 +entry player_slip_jabu2 +entry player_slip_jabu2 +entry player_slip_lava2 +entry player_slip_jabu2 +entry player_slip_grass2 +entry player_slip_dirt2 +entry player_slip_unused2 +entry player_slip_unused2 +entry player_child_step_water +entry player_slip_unused2 +entry player_slip_iron_boots_unused +entry player_slip_stone2 + +.channel player_child_step_dirt +ldlayer 0, layer_2A7 +end + +.layer layer_2A5 +transpose -2 + +.layer layer_2A7 +instr FONT00_INSTR_STEP_GROUND +notedv PITCH_E3, 0x15, 56 +end + +.layer layer_2AD +transpose -6 +ldelay 0xD +instr FONT00_INSTR_SWORD_STRIKE +notedvg PITCH_D4, 0x4, 36, 127 +instr FONT00_INSTR_STEP_FIRE +notedv PITCH_G3, 0x4, 56 +end + +.channel player_child_step_sand +ldlayer 0, layer_2C3 +end + +.layer layer_2C1 +transpose -2 + +.layer layer_2C3 +instr FONT00_INSTR_STEP_SAND +notedv PITCH_A3, 0x15, 56 +end + +.channel player_child_step_stone +ldi 20 +stio 1 +ldlayer 0, layer_2D2 +end + +.layer layer_2D0 +transpose -2 + +.layer layer_2D2 +instr FONT00_INSTR_STEP_ROCK +notedv PITCH_GF3, 0x15, 95 +end + +.channel player_child_step_jabu +ldlayer 0, layer_2DE +end + +.layer layer_2DC +transpose -2 + +.layer layer_2DE +instr FONT00_INSTR_STEP_JABU +portamento 0x82, 31, 255 +notedv PITCH_A3, 0x2D, 93 +end + +.channel player_child_step_water +ldlayer 0, layer_2EE +end + +.layer layer_2EC +transpose -2 + +.layer layer_2EE +instr FONT00_INSTR_STEP_WATER +notedv PITCH_A3, 0x1E, 56 +end + +.channel player_child_step_water_deep +ldlayer 0, layer_2FA +end + +.layer layer_2F8 +transpose -2 + +.layer layer_2FA +instr FONT00_INSTR_STEP_WATER +notedv PITCH_F3, 0x1E, 56 +end + +.channel player_child_step_tall_grass +ldlayer 0, layer_306 +end + +.layer layer_304 +transpose -2 + +.layer layer_306 +instr FONT00_INSTR_STEP_CARPET_0 +notedv PITCH_F3, 0x6, 80 +instr FONT00_INSTR_STEP_GRASS +releaserate 235 +notedv PITCH_B3, 0x30, 80 +end + +.channel player_child_step_lava +ldlayer 0, layer_319 +end + +.layer layer_317 +transpose -2 + +.layer layer_319 +instr FONT00_INSTR_STEP_GROUND +notedv PITCH_C3, 0x4, 42 +instr FONT00_INSTR_STEP_WATER +notedv PITCH_GF2, 0x6, 56 +instr FONT00_INSTR_BOMB +portamento 0x81, 44, 255 +notedv PITCH_F3, 0x16, 64 +end + +.channel player_child_step_grass +ldlayer 0, layer_333 +end + +.layer layer_331 +transpose -2 + +.layer layer_333 +instr FONT00_INSTR_STEP_CARPET_0 +env envelope_66B0, 250 +notedv PITCH_A3, 0x15, 70 +end + +.channel player_child_step_carpet +ldlayer 0, layer_343 +end + +.layer layer_341 +transpose -2 + +.layer layer_343 +instr FONT00_INSTR_STEP_CARPET_1 +notedv PITCH_GF4, 0x0, 80 +end + +.channel player_child_step_wood +ldlayer 0, layer_34F +end + +.layer layer_34D +transpose -2 + +.layer layer_34F +instr FONT00_INSTR_STEP_WOOD +notedv PITCH_AF3, 0x14, 86 +end + +.channel player_child_step_bridge +ldlayer 0, layer_35B +end + +.layer layer_359 +transpose -2 + +.layer layer_35B +instr FONT00_INSTR_STEP_BRIDGE +notedv PITCH_C3, 0x18, 76 +end + +.channel player_step_vines +ldlayer 0, layer_36A +ldlayer 1, layer_2AD +end + +.layer layer_368 +transpose -2 + +.layer layer_36A +instr FONT00_INSTR_STEP_SAND +notedvg PITCH_DF3, 0x6, 110, 127 +notedv PITCH_E1, 0xA, 110 +ldelay 0x5 +end + +.channel player_step_iron_boots +instr FONT00_INSTR_STEP_IRON +ldlayer 0, layer_37C +end + +.layer layer_37C +notedv PITCH_E3, 0x28, 96 +end + +.channel player_step_unused +ldlayer 0, layer_384 +end + +.layer layer_384 +instr FONT00_INSTR_STEP_SAND +notedv PITCH_A2, 0x2A, 56 +end + +.channel player_child_step_ice +ldlayer 0, layer_390 +end + +.layer layer_38E +transpose -2 + +.layer layer_390 +instr FONT00_INSTR_STEP_ICE +notedv PITCH_A3, 0x15, 85 +end + +.channel player_child_jump_dirt +instr FONT00_INSTR_STEP_GROUND +ldlayer 0, layer_3A1 +ldlayer 1, layer_3AA +end + +.layer layer_39F +transpose -2 + +.layer layer_3A1 +notedv PITCH_E3, 0xA, 63 +notedv PITCH_C4, 0xA, 63 +ldelay 0x7 +end + +.layer layer_3AA +ldelay 0x7 +instr FONT00_INSTR_SWORD_HIT_SHIELD +env envelope_6660, 250 +notedvg PITCH_C5, 0x6, 60, 127 +instr FONT00_INSTR_SWORD_STRIKE +notedvg PITCH_F4, 0x4, 48, 127 +instr FONT00_INSTR_STEP_FIRE +notedv PITCH_F3, 0x5, 55 +notedv PITCH_B3, 0x5, 55 +end + +.channel player_child_jump_sand +ldlayer 0, layer_3CE +ldlayer 1, layer_3AA +end + +.layer layer_3CC +transpose -2 + +.layer layer_3CE +instr FONT00_INSTR_STEP_SAND +notedv PITCH_A3, 0xA, 63 +notedv PITCH_F4, 0xA, 63 +ldelay 0x7 +end + +.channel player_child_jump_stone +ldi 20 +stio 1 +ldlayer 0, layer_3E5 +ldlayer 1, layer_3AA +end + +.layer layer_3E3 +transpose -2 + +.layer layer_3E5 +instr FONT00_INSTR_STEP_ROCK +notedvg PITCH_GF3, 0xA, 95, 127 +notedvg PITCH_B3, 0xA, 95, 127 +ldelay 0x7 +end + +.channel player_child_jump_jabu +ldlayer 0, layer_3FB +ldlayer 1, layer_3AA +end + +.layer layer_3F9 +transpose -2 + +.layer layer_3FB +instr FONT00_INSTR_STEP_JABU +notedv PITCH_F3, 0xA, 63 +notedv PITCH_D4, 0xA, 63 +ldelay 0x7 +end + +.channel player_child_jump_water +ldlayer 0, layer_40F +ldlayer 1, layer_3AA +end + +.layer layer_40D +transpose -2 + +.layer layer_40F +instr FONT00_INSTR_STEP_WATER +notedv PITCH_A3, 0xA, 63 +notedv PITCH_F4, 0x1E, 63 +end + +.channel player_child_jump_water_deep +ldlayer 0, layer_421 +ldlayer 1, layer_3AA +end + +.layer layer_41F +transpose -2 + +.layer layer_421 +instr FONT00_INSTR_STEP_WATER +notedv PITCH_F3, 0xA, 63 +notedv PITCH_D4, 0x1E, 63 +end + +.channel player_child_jump_tall_grass +ldlayer 0, layer_433 +ldlayer 1, layer_3AA +end + +.layer layer_431 +transpose -2 + +.layer layer_433 +instr FONT00_INSTR_STEP_CARPET_0 +notedv PITCH_E3, 0x6, 80 +instr FONT00_INSTR_STEP_GRASS +releaserate 225 +notedv PITCH_A3, 0xA, 75 +notedv PITCH_E4, 0x30, 80 +end + +.channel player_child_jump_lava +ldlayer 0, layer_44C +ldlayer 1, layer_3AA +end + +.layer layer_44A +transpose -2 + +.layer layer_44C +instr FONT00_INSTR_STEP_GROUND +notedv PITCH_BF2, 0x4, 45 +instr FONT00_INSTR_STEP_WATER +notedv PITCH_G2, 0x6, 63 +instr FONT00_INSTR_BOMB +portamento 0x81, 42, 255 +notedv PITCH_E3, 0xE, 49 +instr FONT00_INSTR_STEP_WATER +notedv PITCH_EF3, 0xE, 63 +end + +.channel player_child_jump_grass +ldlayer 0, layer_46E +ldlayer 1, layer_3AA +end + +.layer layer_46C +transpose -2 + +.layer layer_46E +instr FONT00_INSTR_STEP_CARPET_0 +notedv PITCH_G3, 0xA, 63 +notedv PITCH_F4, 0xA, 63 +ldelay 0x7 +end + +.channel player_child_jump_carpet +ldlayer 0, layer_482 +ldlayer 1, layer_3AA +end + +.layer layer_480 +transpose -2 + +.layer layer_482 +instr FONT00_INSTR_STEP_CARPET_1 +notedv PITCH_C4, 0xA, 78 +notedv PITCH_A4, 0xA, 78 +ldelay 0x7 +end + +.channel player_child_jump_wood +ldlayer 0, layer_496 +ldlayer 1, layer_3AA +end + +.layer layer_494 +transpose -2 + +.layer layer_496 +instr FONT00_INSTR_STEP_WOOD +notedv PITCH_AF3, 0xA, 73 +notedv PITCH_F4, 0x1E, 73 +end + +.channel player_child_jump_bridge +ldlayer 0, layer_4A8 +ldlayer 1, layer_3AA +end + +.layer layer_4A6 +transpose -2 + +.layer layer_4A8 +instr FONT00_INSTR_STEP_BRIDGE +notedv PITCH_F3, 0xA, 63 +notedv PITCH_B3, 0x19, 63 +end + +.channel player_jump_iron_boots +instr FONT00_INSTR_STEP_IRON +ldlayer 0, layer_4B7 +end + +.layer layer_4B7 +notedv PITCH_EF3, 0xA, 96 +notedv PITCH_A3, 0x18, 96 +end + +.layer layer_unused_4BE +transpose 2 +portamento 0x85, 26, 255 +notedv PITCH_EF2, 0xA, 80 +legato +transpose 5 +portamento 0x85, 26, 255 +notedv PITCH_EF2, 0xF, 80 +notedv PITCH_EF2, 0x12, 80 +notedv PITCH_G2, 0xF, 80 +end + +.channel player_jump_unused +ldlayer 0, layer_4DF +ldlayer 1, layer_3AA +end + +.layer layer_4DF +instr FONT00_INSTR_STEP_SAND +notedv PITCH_A2, 0x12, 63 +notedv PITCH_F3, 0x12, 63 +ldelay 0x7 +end + +.channel player_child_jump_ice +ldlayer 0, layer_4F3 +ldlayer 1, layer_3AA +end + +.layer layer_4F1 +transpose -2 + +.layer layer_4F3 +instr FONT00_INSTR_STEP_ICE +notedv PITCH_E3, 0x7, 95 +notedv PITCH_B4, 0x12, 95 +ldelay 0x7 +end + +.channel player_child_land_dirt +ldlayer 0, layer_507 +ldlayer 1, layer_512 +end + +.layer layer_505 +transpose -2 + +.layer layer_507 +instr FONT00_INSTR_STEP_GROUND +notedv PITCH_E4, 0xA, 75 +notedv PITCH_E3, 0xA, 75 +ldelay 0x7 +end + +.layer layer_512 +ldelay 0x7 +instr FONT00_INSTR_SWORD_HIT_SHIELD +env envelope_6660, 250 +notedvg PITCH_C5, 0x6, 39, 127 +instr FONT00_INSTR_SWORD_STRIKE +notedvg PITCH_D4, 0x4, 49, 127 +instr FONT00_INSTR_STEP_FIRE +notedv PITCH_B3, 0x5, 39 +notedv PITCH_F3, 0x5, 39 +end + +.channel player_child_land_sand +ldlayer 0, layer_536 +ldlayer 1, layer_512 +end + +.layer layer_534 +transpose -2 + +.layer layer_536 +instr FONT00_INSTR_STEP_SAND +notedv PITCH_A4, 0xA, 75 +notedv PITCH_A3, 0xA, 75 +end + +.channel player_child_land_stone +ldi 20 +stio 1 +ldlayer 0, layer_54B +ldlayer 1, layer_512 +end + +.layer layer_549 +transpose -2 + +.layer layer_54B +instr FONT00_INSTR_STEP_ROCK +notedvg PITCH_GF4, 0xA, 101, 64 +notedvg PITCH_GF3, 0xA, 101, 64 +ldelay 0x7 +end + +.channel player_child_land_jabu +ldlayer 0, layer_561 +ldlayer 1, layer_512 +end + +.layer layer_55F +transpose -2 + +.layer layer_561 +instr FONT00_INSTR_STEP_JABU +notedv PITCH_F4, 0xA, 75 +notedv PITCH_F3, 0xA, 75 +ldelay 0x7 +end + +.channel player_child_land_water +ldlayer 0, layer_575 +ldlayer 1, layer_512 +end + +.layer layer_573 +transpose -2 + +.layer layer_575 +instr FONT00_INSTR_STEP_WATER +notedv PITCH_A4, 0xA, 75 +notedv PITCH_A3, 0x1E, 75 +end + +.channel player_child_land_water_deep +ldlayer 0, layer_587 +ldlayer 1, layer_512 +end + +.layer layer_585 +transpose -2 + +.layer layer_587 +instr FONT00_INSTR_STEP_WATER +notedv PITCH_F4, 0xA, 75 +notedv PITCH_F3, 0x1E, 75 +end + +.channel player_child_land_tall_grass +ldlayer 0, layer_599 +ldlayer 1, layer_512 +end + +.layer layer_597 +transpose -2 + +.layer layer_599 +instr FONT00_INSTR_STEP_CARPET_0 +notedv PITCH_A3, 0x6, 56 +instr FONT00_INSTR_STEP_GRASS +releaserate 225 +notedv PITCH_F4, 0xA, 80 +notedv PITCH_A3, 0x30, 80 +end + +.channel player_child_land_lava +ldlayer 0, layer_5B2 +ldlayer 1, layer_512 +end + +.layer layer_5B0 +transpose -2 + +.layer layer_5B2 +instr FONT00_INSTR_STEP_GROUND +notedv PITCH_B2, 0x4, 68 +instr FONT00_INSTR_STEP_WATER +notedv PITCH_F3, 0x6, 75 +notedv PITCH_G2, 0xA, 75 +instr FONT00_INSTR_BOMB +portamento 0x81, 38, 255 +notedv PITCH_C3, 0x16, 70 +end + +.channel player_child_land_grass +ldlayer 0, layer_5D2 +ldlayer 1, layer_512 +end + +.layer layer_5D0 +transpose -2 + +.layer layer_5D2 +instr FONT00_INSTR_STEP_CARPET_0 +notedv PITCH_E4, 0xA, 75 +notedv PITCH_G3, 0xA, 75 +ldelay 0x7 +end + +.channel player_child_land_carpet +ldlayer 0, layer_5E6 +ldlayer 1, layer_512 +end + +.layer layer_5E4 +transpose -2 + +.layer layer_5E6 +instr FONT00_INSTR_STEP_CARPET_1 +notedv PITCH_B4, 0xA, 90 +notedv PITCH_F3, 0xA, 90 +ldelay 0x7 +end + +.channel player_child_land_wood +ldlayer 0, layer_5FA +ldlayer 1, layer_512 +end + +.layer layer_5F8 +transpose -2 + +.layer layer_5FA +instr FONT00_INSTR_STEP_WOOD +notedv PITCH_AF4, 0xA, 85 +notedv PITCH_AF3, 0x1E, 85 +end + +.channel player_child_land_bridge +ldlayer 0, layer_60C +ldlayer 1, layer_512 +end + +.layer layer_60A +transpose -2 + +.layer layer_60C +instr FONT00_INSTR_STEP_BRIDGE +notedv PITCH_F4, 0xA, 75 +notedv PITCH_F3, 0x1E, 75 +end + +.channel player_land_iron_boots +instr FONT00_INSTR_STEP_IRON +ldlayer 0, layer_61B +end + +.layer layer_61B +notedv PITCH_B3, 0xA, 96 +notedv PITCH_F3, 0x18, 96 +end + +.channel player_land_unused +ldlayer 0, layer_629 +ldlayer 1, layer_512 +end + +.layer layer_629 +instr FONT00_INSTR_STEP_SAND +notedv PITCH_A3, 0x12, 75 +notedv PITCH_A2, 0x12, 75 +end + +.channel player_child_land_ice +ldlayer 0, layer_63B +ldlayer 1, layer_512 +end + +.layer layer_639 +transpose -2 + +.layer layer_63B +instr FONT00_INSTR_STEP_ICE +notedv PITCH_G4, 0x5, 98 +notedv PITCH_E3, 0x12, 98 +end + +.channel player_climb_down_vine_top +instr FONT00_INSTR_DROP +env envelope_667C +ldlayer 0, layer_64D +end + +.layer layer_64D +portamento 1, 48, 0x10 +notedv PITCH_D4, 0x18, 100 +end + +.channel player_climb_up_vine_top +instr FONT00_INSTR_WATER_SPLASH_S +env envelope_6694 +ldlayer 0, layer_65E +end + +.layer layer_65E +notedv PITCH_A4, 0x16, 127 +end + +.channel player_climb_on_epona +instr FONT00_INSTR_STEP_CARPET_0 +env envelope_6674 +ldlayer 0, layer_66B +end + +.layer layer_66B +notedv PITCH_A2, 0xA, 105 +end + +.channel player_jump_off_epona +instr FONT00_INSTR_WATER_SPLASH_S +env envelope_6694 +ldlayer 0, layer_678 +end + +.layer layer_678 +portamento 0x81, 48, 255 +notedv PITCH_C4, 0x20, 60 +end + +.channel player_shield_epona +instr FONT00_INSTR_WATER_SPLASH_S +env envelope_6688 +ldlayer 0, layer_693 +ldlayer 1, layer_68C +end + +.layer layer_68C +notedv PITCH_F2, 0x6, 115 +notedv PITCH_C3, 0xC, 115 +end + +.layer layer_693 +instr FONT00_INSTR_SWORD_SHEATHE +portamento 0x81, 20, 255 +notedv PITCH_E3, 0x19, 90 +end + +.channel player_change_item_held +instr FONT00_INSTR_WATER_SPLASH_S +env envelope_66E0 +ldlayer 0, layer_6A9 +ldlayer 1, layer_6B5 +end + +.layer layer_6A9 +notedv PITCH_G3, 0x6, 115 +notedv PITCH_C3, 0xC, 115 +instr FONT00_INSTR_SWORD_SHEATHE +notedv PITCH_D4, 0xF, 90 +end + +.layer layer_6B5 +instr FONT00_INSTR_SWORD_SHEATHE +portamento 0x81, 31, 255 +notedv PITCH_F2, 0x19, 90 +end + +.channel player_catch_boomerang +instr FONT00_INSTR_STEP_GROUND +ldlayer 0, layer_6C5 +end + +.layer layer_6C5 +portamento 0x81, 27, 200 +notedv PITCH_F3, 0x7, 127 +end + +.channel player_large_splash +instr FONT00_INSTR_WATER_SPLASH +env envelope_65FC +releaserate 127 +ldlayer 0, layer_6D8 +end + +.layer layer_6D8 +portamento 0x81, 39, 200 +notedv PITCH_F3, 0x91, 100 +end + +.channel player_small_splash +instr FONT00_INSTR_WATER_SPLASH +env envelope_6610 +ldlayer 0, layer_6EA +end + +.layer layer_6EA +portamento 0x81, 34, 48 +notedv PITCH_A3, 0x50, 105 +end + +.channel player_swim +ldlayer 0, layer_6F8 +end + +.layer layer_unused_6F6 +transpose -6 + +.layer layer_6F8 +instr FONT00_INSTR_WATER_SWIM +env envelope_6624, 251 +portamento 0x81, 36, 200 +notedv PITCH_C3, 0x30, 105 +end + +.channel player_throw +instr FONT00_INSTR_SWORD_MISS +ldlayer 0, layer_70C +end + +.layer layer_70C +portamento 0x81, 27, 255 +notedv PITCH_C2, 0x18, 100 +end + +.channel player_hit_wall_old +gain 15 +ldlayer 0, layer_71A +end + +.layer layer_71A +call layer_fn_725 +portamento 0x81, 45, 255 +notedv PITCH_B2, 0xE, 115 +end + +.layer layer_fn_725 +instr FONT00_INSTR_SLAM_GUNSHOT +env envelope_66B0, 245 +end + +.layer layer_unused_72C +transpose 2 +jump layer_800 + +.channel player_flip +instr FONT00_INSTR_SWORD_MISS +ldlayer 0, layer_737 +end + +.layer layer_737 +legato +portamento 0x85, 29, 225 +notedv PITCH_D2, 0x8, 100 +notedv PITCH_D1, 0x14, 100 +end + +.channel player_sidejump +ldlayer 0, layer_747 +end + +.layer layer_747 +instr FONT00_INSTR_SWORD_MISS +releaserate 248 +portamento 0x81, 26, 225 +notedv PITCH_GF1, 0xC, 100 +end + +.channel player_hit_blunt +gain 20 +ldlayer 0, layer_1B3F +ldlayer 1, layer_71A +ldlayer 2, layer_75F +end + +.layer layer_75F +call layer_fn_725 +portamento 0x85, 34, 255 +notedv PITCH_BF3, 0x7, 110 +end + +.channel player_hit_stab +instr FONT00_INSTR_SWORD_SWING +env envelope_66C8 +ldlayer 0, layer_776 +ldlayer 1, layer_785 +end + +.layer layer_776 +portamento 0x81, 55, 127 +notedv PITCH_DF1, 0x8, 115 +portamento 0x81, 6, 255 +notedv PITCH_AF3, 0xB, 105 +end + +.layer layer_785 +instr FONT00_INSTR_WHISTLE_AIR +portamento 0x81, 49, 222 +notedv PITCH_BF2, 0x8, 115 +portamento 0x81, 19, 255 +notedv PITCH_F3, 0xC, 115 +end + +.channel player_slip_dirt +ldlayer 0, layer_79D +ldlayer 1, layer_E0C +end + +.layer layer_79D +ldelay 0x30 +end + +.channel player_slip_sand +ldlayer 0, layer_79D +ldlayer 1, layer_E1C +end + +.channel player_slip_stone +ldlayer 0, layer_79D +ldlayer 1, layer_E24 +end + +.channel player_slip_jabu +ldlayer 0, layer_79D +ldlayer 1, layer_E34 +end + +.channel player_slip_water +ldlayer 0, layer_79D +ldlayer 1, layer_E34 +end + +.channel player_slip_water_deep +ldlayer 0, layer_79D +ldlayer 1, layer_E34 +end + +.channel player_slip_tall_grass +ldlayer 0, layer_79D +ldlayer 1, layer_E3C +end + +.channel player_slip_lava +ldlayer 0, layer_79D +ldlayer 1, layer_E34 +end + +.channel player_slip_grass +ldlayer 0, layer_79D +ldlayer 1, layer_E4C +end + +.channel player_slip_carpet +ldlayer 0, layer_79D +ldlayer 1, layer_E0C +end + +.channel player_slip_wood +ldlayer 0, layer_79D +ldlayer 1, layer_E54 +end + +.channel player_slip_bridge +ldlayer 0, layer_79D +ldlayer 1, layer_E54 +end + +.channel player_slip_unused +ldlayer 0, layer_79D +ldlayer 1, layer_E64 +end + +.channel player_rebound_dirt +ldlayer 1, layer_80C +.channel chan_7F7 +gain 25 +ldlayer 2, layer_512 + +.channel player_rebound_unarmed +ldlayer 0, layer_800 +end + +.layer layer_800 +call layer_fn_725 +portamento 0x81, 38, 200 +notedvg PITCH_BF3, 0x24, 115, 100 +end + +.layer layer_80C +transpose -6 +jump layer_507 + +.channel player_rebound_sand +ldlayer 1, layer_816 +rjump chan_7F7 + +.layer layer_816 +transpose -6 +jump layer_536 + +.channel player_rebound_stone +ldlayer 1, layer_820 +rjump chan_7F7 + +.layer layer_820 +transpose -6 +jump layer_54B + +.channel player_rebound_jabu +ldlayer 1, layer_82A +rjump chan_7F7 + +.layer layer_82A +transpose -6 +jump layer_561 + +.channel player_rebound_water +ldlayer 1, layer_834 +rjump chan_7F7 + +.layer layer_834 +transpose -6 +jump layer_575 + +.channel chan_unused_839 +rjump chan_7F7 + +.channel player_rebound_water_deep +ldlayer 1, layer_840 +rjump chan_7F7 + +.layer layer_840 +transpose -6 +jump layer_587 + +.channel player_rebound_tall_grass +ldlayer 1, layer_84A +rjump chan_7F7 + +.layer layer_84A +transpose -6 +jump layer_599 + +.channel player_rebound_lava +ldlayer 1, layer_854 +rjump chan_7F7 + +.layer layer_854 +transpose -6 +jump layer_5B2 + +.channel player_rebound_grass +ldlayer 1, layer_85E +rjump chan_7F7 + +.layer layer_85E +transpose -6 +jump layer_5D2 + +.channel player_rebound_carpet +ldlayer 1, layer_868 +rjump chan_7F7 + +.layer layer_868 +transpose -6 +jump layer_5E6 + +.channel player_rebound_wood +ldlayer 1, layer_872 +rjump chan_7F7 + +.layer layer_872 +transpose -6 +jump layer_5FA + +.channel player_rebound_bridge +ldlayer 1, layer_87D +jump chan_7F7 + +.layer layer_87D +transpose -6 +jump layer_60C + +.channel player_rebound_unused +ldlayer 1, layer_888 +jump chan_7F7 + +.layer layer_888 +transpose -6 +jump layer_629 + +.channel player_rebound_ice +ldlayer 1, layer_893 +jump chan_7F7 + +.layer layer_893 +transpose -6 +jump layer_63B + +.channel player_dive_surface +ldlayer 0, layer_89C +end + +.layer layer_89C +instr FONT00_INSTR_WATER_SPLISH +env envelope_66EC, 251 +portamento 0x81, 39, 255 +notedv PITCH_C5, 0x18, 100 +instr FONT00_INSTR_WATER_SPLASH +env envelope_67A4, 221 +portamento 0x81, 32, 200 +notedv PITCH_C4, 0x3C, 100 +end + +.channel player_dive_down +ldlayer 0, layer_8BB +end + +.layer layer_8BB +instr FONT00_INSTR_WATER_BUBBLES +env envelope_65FC, 221 +portamento 1, 46, 72 +notedv PITCH_G3, 0xDC, 100 +end + +.channel player_dive_move +ldlayer 0, layer_8CE +end + +.layer layer_8CE +instr FONT00_INSTR_WATER_BUBBLES +env envelope_65D8, 251 +portamento 0x81, 39, 255 +notedv PITCH_E4, 0x60, 100 +end + +.channel player_child_metalequip +ldlayer 0, layer_2AD +end + +.channel player_adult_metalequip +ldlayer 0, layer_B7D +end + +.channel player_electric_shock +instr FONT00_INSTR_POTTERY_ELECTRIC +env envelope_6674 +ldlayer 0, layer_903 +.channel chan_8EC +rand 10 +stseq 2, layer_903+1 +stseq 2, chan_8FC+1 +rand 12 +stseq 92, layer_903 +.channel chan_8FC +ldi 1 +call delay_varyingvol +rjump chan_8EC + +.layer layer_903 +notedv PITCH_C3, 0x50, 80 +ldelay 0x5 +rjump layer_903 + +.channel player_lift_grass +ldlayer 1, layer_936 +ldlayer 0, layer_911 +end + +.layer layer_911 +instr FONT00_INSTR_STEP_GROUND +notedv PITCH_A3, 0xA, 64 +instr FONT00_INSTR_STEP_GRASS +notedv PITCH_D4, 0x18, 90 +end + +.channel player_lift_rock +gain 20 +ldlayer 0, layer_927 +ldlayer 1, layer_936 +end + +.layer layer_925 +transpose -4 + +.layer layer_927 +instr FONT00_INSTR_STEP_GROUND +portamento 0x83, 27, 255 +notedv PITCH_E2, 0x6, 80 +instr FONT00_INSTR_STEP_CARPET_0 +notedv PITCH_E3, 0xF, 95 +end + +.layer layer_936 +instr FONT00_INSTR_EXPLOSION_0 +portamento 0x81, 22, 255 +notedv PITCH_A5, 0x1E, 50 +end + +.channel player_morpha_bubble +ldlayer 0, layer_944 +end + +.layer layer_944 +instr FONT00_INSTR_WATER_BUBBLES +legato +.layer layer_947 +portamento 0x81, 15, 255 +notedv PITCH_E2, 0x60, 75 +rjump layer_947 + +.channel player_lift_giant_rock +gain 20 +ldlayer 0, layer_925 +ldlayer 1, layer_2D55 +end + +.channel player_sword_charge +instr FONT00_INSTR_SYNTH +env envelope_66EC +ldlayer 0, layer_962 +end + +.layer layer_962 +portamento 0x81, 36, 255 +notedv PITCH_C4, 0x64, 95 +end + +.channel player_freeze +gain 30 +ldlayer 0, layer_973 +ldlayer 1, layer_97E +end + +.layer layer_973 +instr FONT00_INSTR_FIRE_WIND +portamento 0x81, 43, 255 +notedv PITCH_E3, 0xB4, 105 +end + +.layer layer_97E +instr FONT00_INSTR_CLOTH_TEAR +portamento 0x81, 20, 255 +notedv PITCH_B1, 0xB4, 88 +end + +.channel player_lift_pot +ldlayer 0, layer_990 +ldlayer 1, layer_99A +end + +.layer layer_990 +transpose 50 +.layer layer_992 +instr FONT00_INSTR_POTTERY_ELECTRIC +notedv PITCH_C2, 0x6, 72 +end + +.layer layer_998 +transpose -4 + +.layer layer_99A +instr FONT00_INSTR_STEP_IRON +notedv PITCH_B3, 0x3, 110 +end + +.channel player_hit_unused +ldlayer 0, layer_9A4 +end + +.layer layer_9A4 +instr FONT00_INSTR_SLAM_GUNSHOT +env envelope_664C, 253 +notedv PITCH_BF3, 0x5, 100 +end + +.channel player_idle_shuffle +ldlayer 0, layer_9B2 +end + +.layer layer_9B2 +instr FONT00_INSTR_EXPLOSION_0 +env envelope_66E0, 251 +notedv PITCH_EF3, 0xA, 80 +end + +.channel player_idle_slide +ldlayer 0, layer_9C0 +end + +.layer layer_9C0 +instr FONT00_INSTR_WATER_SPLASH +env envelope_66E0, 251 +notedv PITCH_C3, 0x15, 80 +end + +.channel player_dive_unused +ldlayer 0, layer_9CE +end + +.layer layer_9CE +instr FONT00_INSTR_WATER_SPLISH +env envelope_66EC, 251 +portamento 0x81, 39, 255 +notedv PITCH_C3, 0xC, 100 +instr FONT00_INSTR_WATER_SPLASH +env envelope_67A4, 221 +portamento 0x81, 36, 200 +notedv PITCH_C3, 0x3C, 100 +end + +.channel player_freeze_short +gain 30 +ldlayer 0, layer_9F2 +ldlayer 1, layer_9FC +end + +.layer layer_9F2 +instr FONT00_INSTR_FIRE_WIND +portamento 0x81, 43, 255 +notedv PITCH_E3, 0x1C, 105 +end + +.layer layer_9FC +instr FONT00_INSTR_CLOTH_TEAR +portamento 0x81, 20, 255 +notedv PITCH_B1, 0x1C, 88 +end + +.channel player_ice_break +ldlayer 0, layer_A0A +end + +.layer layer_A0A +instr FONT00_INSTR_CHATTER +transpose 48 +notedv PITCH_F3, 0x14, 100 +notedv PITCH_A3, 0x0, 105 +end + +.channel player_slip_ice +instr FONT00_INSTR_SLIDE_HEAVY +env envelope_66FC +ldlayer 0, layer_A1E +end + +.layer layer_A1E +notedv PITCH_DF4, 0x7D00, 64 +end + +.channel player_sheathe_item_unused +instr FONT00_INSTR_WATER_SPLASH_S +env envelope_66EC +ldlayer 0, layer_A2C +end + +.layer layer_A2C +notedv PITCH_F3, 0x5, 75 +notedv PITCH_BF2, 0xA, 75 +notedv PITCH_BF2, 0x11, 75 +end + +.channel player_lift_crate +ldlayer 0, layer_A3A +end + +.layer layer_A3A +instr FONT00_INSTR_STICK_ATTACK +notedv PITCH_A2, 0x6, 100 +end + +.channel player_cast_fire +ldlayer 0, layer_A4C +ldlayer 1, layer_A5D +ldlayer 2, layer_A6E +jump chan_118F + +.layer layer_A4C +instr FONT00_INSTR_FLAME_THUNDER +releaserate 221 +legato +portamento 0x85, 0, 255 +notedv PITCH_A2, 0xFA, 74 +notedv PITCH_A4, 0x64, 74 +end + +.layer layer_A5D +instr FONT00_INSTR_EXPLOSION_0 +releaserate 221 +noteldv PITCH_A3, 0x1E, 100 +portamento 0x81, 0, 255 +notedv PITCH_A3, 0x140, 85 +end + +.layer layer_A6E +instr FONT00_INSTR_FAIRY_MAGIC +releaserate 221 +portamento 0x81, 0, 255 +notedv PITCH_A4, 350, 80 +end + +.channel player_cast_wind +ldlayer 0, layer_A85 +ldlayer 1, layer_A9E +ldlayer 2, layer_AAF +end + +.layer layer_A85 +call layer_fn_A95 +legato +portamento 0x85, 62, 255 +notedv PITCH_C4, 0x3C, 85 +notedv PITCH_F5, 500, 85 +end + +.layer layer_fn_A95 +instr FONT00_INSTR_WIND_HOWL_S +env envelope_6808, 200 +transpose 12 +end + +.layer layer_A9E +portamento 0x81, 32, 255 +instr FONT00_INSTR_SLIDE_LINK +transpose 24 +env envelope_66F4, 200 +notedv PITCH_F5, 0x230, 40 +end + +.layer layer_AAF +instr FONT00_INSTR_WARP +transpose 12 +env envelope_67D8, 200 +notedv PITCH_F5, 0x230, 70 +end + +.channel player_cast_wind_return +instr FONT00_INSTR_WARP +gain 15 +ldlayer 0, layer_2130 +ldlayer 1, layer_2124 +ldlayer 2, layer_2D3A +ldi 80 +call delay_varyingvol +ldlayer 0, layer_AD5 +ldlayer 2, layer_210B +end + +.layer layer_AD5 +ldelay 0x30 +end + +.channel player_cast_soul +ldi 0 +.channel chan_ADA +stseq 244, layer_AFD+1 +stseq 12, layer_AF2+1 +vibfreq 255 +instr FONT00_INSTR_WARP +env envelope_6818 +releaserate 235 +ldlayer 0, layer_AFD +ldlayer 1, layer_AF2 +end + +.layer layer_AF2 +transpose 36 +portamento 0x83, 44, 127 +.layer layer_AF8 +notedv PITCH_A4, 0x60, 64 +rjump layer_AF8 + +.layer layer_AFD +transpose 12 +portamento 0x83, 44, 127 +.layer layer_B03 +notedv PITCH_A4, 0x60, 64 +rjump layer_B03 + +.channel player_arrow_fire_charge +ldlayer 0, layer_B23 +ldlayer 2, layer_B1D +ldi 1 +call delay_varyingvol +ldlayer 1, layer_B2F +vibfreq 96 +vibdepthgrad 128, 128, 0 +end + +.layer layer_B1D +instr FONT00_INSTR_IGNITE +notedv PITCH_A3, 0x0, 110 +end + +.layer layer_B23 +instr FONT00_INSTR_WIND_HOWL_S +env envelope_66FC, 245 +legato +.layer layer_B2A +notedv PITCH_A3, 0x64, 74 +rjump layer_B2A + +.layer layer_B2F +instr FONT00_INSTR_FAIRY_MAGIC +legato +.layer layer_B32 +notedv PITCH_D3, 0x0, 35 +rjump layer_B32 + +.channel player_arrow_ice_charge +ldlayer 0, layer_B47 +ldlayer 1, layer_B41 +ldlayer 2, layer_B57 +end + +.layer layer_B41 +instr FONT00_INSTR_WARP +transpose 16 +rjump layer_B49 + +.layer layer_B47 +instr FONT00_INSTR_SHIMMER +.layer layer_B49 +env envelope_6818, 245 +legato +portamento 0x81, 39, 200 +.layer layer_B52 +notedv PITCH_E4, 0x3C, 60 +rjump layer_B52 + +.layer layer_B57 +instr FONT00_INSTR_IGNITE +notedv PITCH_F4, 0x0, 110 +end + +.channel player_arrow_light_charge +ldlayer 0, layer_B6D +ldlayer 1, layer_B67 +ldlayer 2, layer_B57 +end + +.layer layer_B67 +instr FONT00_INSTR_WARP +transpose 16 +rjump layer_B6F + +.layer layer_B6D +instr FONT00_INSTR_FAIRY +.layer layer_B6F +env envelope_66C8, 240 +legato +.layer layer_B74 +notedv PITCH_G4, 0x51, 42 +rjump layer_B74 + +.channel player_adult_step_dirt +ldlayer 0, layer_2A5 +end + +.layer layer_B7D +ldelay 0x8 +transpose -6 +instr FONT00_INSTR_SWORD_SHEATHE +releaserate 255 +notedvg PITCH_BF3, 0x4, 64, 64 +instr FONT00_INSTR_SWORD_STRIKE +notedv PITCH_DF3, 0x5, 24 +instr FONT00_INSTR_SWORD_STRIKE +transpose 48 +notedv PITCH_AF3, 0x4, 38 +end + +.channel player_adult_step_sand +ldlayer 0, layer_2C1 +end + +.channel player_adult_step_stone +ldlayer 0, layer_2D0 +end + +.channel player_adult_step_jabu +ldlayer 0, layer_2DC +end + +.channel player_adult_step_water +ldlayer 0, layer_2EC +end + +.channel player_adult_step_water_deep +ldlayer 0, layer_2F8 +end + +.channel player_adult_step_tall_grass +ldlayer 0, layer_304 +end + +.channel player_adult_step_lava +ldlayer 0, layer_317 +end + +.channel player_adult_step_grass +ldlayer 0, layer_331 +end + +.channel player_adult_step_carpet +ldlayer 0, layer_341 +end + +.channel player_adult_step_wood +ldlayer 0, layer_34D +end + +.channel player_adult_step_bridge +ldlayer 0, layer_359 +end + +.channel player_adult_step_vine +ldlayer 0, layer_368 +ldlayer 1, layer_B7D +end + +.channel player_adult_step_ice +ldlayer 0, layer_38E +end + +.channel player_adult_jump_dirt +instr FONT00_INSTR_STEP_GROUND +ldlayer 0, layer_39F +ldlayer 1, layer_BD6 +end + +.layer layer_BD6 +ldelay 0x8 +instr FONT00_INSTR_SWORD_SHEATHE +releaserate 255 +notedvg PITCH_C4, 0x4, 90, 64 +instr FONT00_INSTR_SWORD_STRIKE +notedv PITCH_E3, 0x5, 38 +instr FONT00_INSTR_SWORD_STRIKE +transpose 48 +notedv PITCH_C4, 0x4, 55 +end + +.channel player_adult_jump_sand +ldlayer 0, layer_3CC +ldlayer 1, layer_BD6 +end + +.channel player_adult_jump_stone +ldlayer 0, layer_3E3 +ldlayer 1, layer_BD6 +end + +.channel player_adult_jump_jabu +ldlayer 0, layer_3F9 +ldlayer 1, layer_BD6 +end + +.channel player_adult_jump_water +ldlayer 0, layer_40D +ldlayer 1, layer_BD6 +end + +.channel player_adult_jump_water_deep +ldlayer 0, layer_41F +end + +.channel player_adult_jump_tall_grass +ldlayer 0, layer_431 +ldlayer 1, layer_BD6 +end + +.channel player_adult_jump_lava +ldlayer 0, layer_44A +ldlayer 1, layer_BD6 +end + +.channel player_adult_jump_grass +ldlayer 0, layer_46C +ldlayer 1, layer_BD6 +end + +.channel player_adult_jump_carpet +ldlayer 0, layer_480 +ldlayer 1, layer_BD6 +end + +.channel player_adult_jump_wood +ldlayer 0, layer_494 +ldlayer 1, layer_BD6 +end + +.channel player_adult_jump_bridge +ldlayer 0, layer_4A6 +ldlayer 1, layer_BD6 +end + +.channel player_adult_jump_ice +ldlayer 0, layer_4F1 +ldlayer 1, layer_BD6 +end + +.channel player_adult_land_dirt +ldlayer 0, layer_505 +ldlayer 1, layer_C45 +end + +.layer layer_C45 +ldelay 0x8 +instr FONT00_INSTR_SWORD_SHEATHE +releaserate 255 +notedvg PITCH_D4, 0x4, 90, 64 +instr FONT00_INSTR_SWORD_STRIKE +notedv PITCH_D3, 0x5, 38 +instr FONT00_INSTR_SWORD_STRIKE +transpose 48 +notedv PITCH_BF3, 0x4, 55 +end + +.channel player_adult_land_sand +ldlayer 0, layer_534 +ldlayer 1, layer_C45 +end + +.channel player_adult_land_stone +ldlayer 0, layer_549 +ldlayer 1, layer_C45 +end + +.channel player_adult_land_jabu +ldlayer 0, layer_55F +ldlayer 1, layer_C45 +end + +.channel player_adult_land_water +ldlayer 0, layer_573 +ldlayer 1, layer_C45 +end + +.channel player_adult_land_water_deep +ldlayer 0, layer_585 +end + +.channel player_adult_land_tall_grass +ldlayer 0, layer_597 +ldlayer 1, layer_C45 +end + +.channel player_adult_land_lava +ldlayer 0, layer_5B0 +ldlayer 1, layer_C45 +end + +.channel player_adult_land_grass +ldlayer 0, layer_5D0 +ldlayer 1, layer_C45 +end + +.channel player_adult_land_carpet +ldlayer 0, layer_5E4 +ldlayer 1, layer_C45 +end + +.channel player_adult_land_wood +ldlayer 0, layer_5F8 +ldlayer 1, layer_C45 +end + +.channel player_adult_land_bridge +ldlayer 0, layer_60A +ldlayer 1, layer_C45 +end + +.channel player_adult_land_ice +ldlayer 0, layer_639 +ldlayer 1, layer_C45 +end + +.channel player_crawl_dirt +ldlayer 0, layer_2A5 +ldi 2 +call delay_varyingvol +jump player_slip_dirt + +.channel player_crawl_sand +ldlayer 0, layer_2C1 +ldi 5 +call delay_varyingvol +jump player_slip_sand + +.channel player_crawl_stone +ldlayer 0, layer_2D0 +ldi 2 +call delay_varyingvol +jump player_slip_stone + +.channel player_crawl_jabu +ldlayer 0, layer_2DC +ldi 5 +call delay_varyingvol +jump player_slip_jabu + +.channel player_crawl_water +ldlayer 0, layer_2EC +ldi 5 +call delay_varyingvol +jump player_slip_water + +.channel player_crawl_water_deep +ldlayer 0, layer_2F8 +ldi 5 +call delay_varyingvol +jump player_slip_water_deep + +.channel player_crawl_tall_grass +ldlayer 0, layer_304 +ldi 5 +call delay_varyingvol +jump player_slip_tall_grass + +.channel player_crawl_lava +ldlayer 0, layer_317 +ldi 5 +call delay_varyingvol +jump player_slip_lava + +.channel player_crawl_grass +ldlayer 0, layer_331 +ldi 5 +call delay_varyingvol +jump player_slip_grass + +.channel player_crawl_carpet +ldlayer 0, layer_341 +ldi 5 +call delay_varyingvol +jump player_slip_carpet + +.channel player_crawl_wood +ldlayer 0, layer_34D +ldi 5 +call delay_varyingvol +jump player_slip_wood + +.channel player_crawl_bridge +ldlayer 0, layer_359 +ldi 1 +call delay_varyingvol +jump player_slip_bridge + +.channel player_crawl_ice +ldlayer 0, layer_38E +ldi 5 +call delay_varyingvol +jump player_slip_stone + +.channel player_cast_soul_end +vibdepth 20 +ldi 4 +jump chan_ADA + +.channel player_roll_dust +ldlayer 0, layer_D47 +end + +.layer layer_D47 +instr FONT00_INSTR_SLIDE_BLOCK +env envelope_66A0, 235 +notedv PITCH_F4, 0xA, 90 +notedv PITCH_G4, 0xE, 90 +notedv PITCH_B4, 0x7F, 75 +end + +.channel player_crash_unused +ldlayer 0, layer_D5E +ldlayer 1, layer_1B3F +end + +.layer layer_D5E +instr FONT00_INSTR_MECH_CHARGE +env envelope_65D8, 228 +notedv PITCH_C5, 0x64, 100 +end + +.channel player_cast_soul_appear +instr FONT00_INSTR_WARP +ldlayer 0, layer_D74 +ldlayer 1, layer_29FC +ldlayer 2, layer_2A01 +end + +.layer layer_D74 +instr FONT00_INSTR_SHIMMER +portamento 0x81, 39, 45 +notedv PITCH_E4, 0x118, 60 +end + +.channel player_fairy_heal +ldlayer 0, layer_D8A +ldlayer 1, layer_D9A +vibfreq 192 +vibdepth 32 +end + +.layer layer_D8A +instr FONTANY_INSTR_SQUARE +env envelope_6818, 221 +legato +portamento 0x81, 36, 64 +.layer layer_D95 +notedv PITCH_A4, 0x78, 34 +rjump layer_D95 + +.layer layer_D9A +instr FONT00_INSTR_FAIRY +env envelope_66FC, 237 +portamento 0x83, 36, 255 +.layer layer_DA4 +notedv PITCH_C4, 0x14, 85 +rjump layer_DA4 + +.channel player_plant_grow +ldlayer 0, layer_DB8 +ldlayer 1, layer_DB6 +.channel chan_DAF +vibfreqgrad 10, 100, 8 +vibdepth 15 +end + +.layer layer_DB6 +transpose 24 + +.layer layer_DB8 +portamento 0x81, 15, 255 + +.layer layer_DBC +instr FONTANY_INSTR_4PULSE +env envelope_6674, 251 +legato +.layer layer_DC3 +notedv PITCH_C4, 500, 35 +rjump layer_DC3 + +.channel player_plant_seed +ldlayer 0, layer_DB6 +rjump chan_DAF + +.channel player_cast_wind_dismiss +instr FONT00_INSTR_WARP +ldlayer 0, layer_DD7 +ldlayer 1, layer_2A01 +end + +.layer layer_DD7 +transpose 30 +legato +portamento 0x81, 43, 64 +notedv PITCH_D4, 0xAA, 80 +end + +.channel player_hover +instr FONT00_INSTR_WARP +vibdepth 9 +vibfreq 128 +env envelope_6818 +releaserate 235 +ldlayer 0, layer_DF2 +end + +.layer layer_DF2 +legato +.layer layer_DF3 +notedv PITCH_E5, 0x7D00, 95 +rjump layer_DF3 + +.channel player_plant_hover +ldlayer 0, layer_DBC +ldlayer 1, layer_E04 +vibfreq 100 +vibdepth 15 +end + +.layer layer_E04 +transpose 24 +rjump layer_DBC + +.channel player_slip_dirt2 +ldlayer 0, layer_E0C +end + +.layer layer_E0C +instr FONT00_INSTR_SLIDE_BLOCK +.layer layer_E0E +env envelope_6704, 251 +legato +.layer layer_E13 +notedv PITCH_C4, 0x7F, 88 +rjump layer_E13 + +.channel player_slip_sand2 +ldlayer 0, layer_E1C +end + +.layer layer_E1C +instr FONT00_INSTR_SLIDE_LINK +rjump layer_E0E + +.channel player_slip_stone2 +ldlayer 0, layer_E24 +end + +.layer layer_E24 +instr FONT00_INSTR_SLIDE_HEAVY +env envelope_6704, 251 +legato +.layer layer_E2B +notedv PITCH_F4, 0x7F, 80 +rjump layer_E2B + +.channel player_slip_jabu2 +ldlayer 0, layer_E34 +end + +.layer layer_E34 +instr FONT00_INSTR_SLIDE_WET +rjump layer_E0E + +.channel player_slip_lava2 +ldlayer 0, layer_E3C +end + +.layer layer_E3C +instr FONT00_INSTR_SLIDE_WET +env envelope_6704, 251 +legato +.layer layer_E43 +notedv PITCH_C4, 0x7F, 86 +rjump layer_E43 + +.channel player_slip_grass2 +ldlayer 0, layer_E4C +end + +.layer layer_E4C +instr FONT00_INSTR_DISTORTION +rjump layer_E0E + +.channel player_slip_unused2 +ldlayer 0, layer_E54 +end + +.layer layer_E54 +instr FONT00_INSTR_SLIDE_HEAVY +env envelope_6704, 251 +legato +.layer layer_E5B +notedv PITCH_AF3, 0x7F, 80 +rjump layer_E5B + +.channel player_slip_iron_boots_unused +ldlayer 0, layer_E64 +end + +.layer layer_E64 +instr FONT00_INSTR_SLIDE_LINK +env envelope_6704, 251 +legato +.layer layer_E6B +notedv PITCH_DF3, 0x7F, 95 +rjump layer_E6B + +.filter filter_player0 +filter 0, 0, 0, 0, 0, 0, 0, 0 + +.filter filter_player1 +filter 0, 0, 0, 0, 0, 0, 0, 0 + +.filter filter_player2 +filter 0, 0, 0, 0, 0, 0, 0, 0 diff --git a/assets/sequences/sfxbanks/system.seq.inc b/assets/sequences/sfxbanks/system.seq.inc new file mode 100644 index 00000000000..55889629757 --- /dev/null +++ b/assets/sequences/sfxbanks/system.seq.inc @@ -0,0 +1,1117 @@ +.table table_system +entry system_menu_open +entry system_menu_close +entry system_puzzle_solved +entry system_rupee +entry system_timer_ding +entry system_error +entry system_error +entry system_treasure_appear +entry system_item_equipped +entry system_cursor +entry system_cursor_cancel +entry system_heart +entry system_z_shift +entry system_menu_unused_down +entry system_map_select_cursor_old +entry system_z_cancel +entry system_z_lock +entry system_menu_unused_down +entry system_menu_unused_up +entry system_camera_mode_toggle +entry system_minimap_toggle +entry system_camera_mode_toggle +entry system_camera_mode_toggle +entry system_z_shift_old +entry system_message_advance +entry system_countdown_caution +entry system_countdown_warn +entry system_low_health +entry system_explosive_boom +entry system_explosive_boom +entry system_navi_call +entry system_magic_refill +entry system_z_lock_old +entry system_unused21 +entry system_unused22 +entry system_title_screen +entry system_get_item +entry system_menu_scroll_left +entry system_menu_scroll_right +entry system_ocarina_system_error +entry system_camera_mode_toggle_old +entry system_minimap_toggle_old +entry system_lens_on +entry system_lens_off +entry system_gerudo_whistle +entry system_minigame_bell +entry system_message_done +entry system_rupee_increase +entry system_z_lock_enemy +entry system_get_treasure_item +entry system_long_whiteout +entry system_whiteout +entry system_warp_in +entry system_shotgun +entry system_metronome +entry system_z_shift_threat +entry system_metronome2 +entry system_file_cursor +entry system_file_select +entry system_file_enter +entry system_file_cancel +entry system_file_error +entry system_equip_fire +entry system_equip_ice +entry system_equip_light +entry system_equip_magic_bow +entry system_metronome3 +entry system_skulltula_token_appears +entry system_silver_rupee +entry system_carrot_recovered +entry system_metronome +entry system_z_shift_threat + +.channel system_menu_open +instr FONTANY_INSTR_SAWTOOTH +env envelope_6660 +releaserate 240 +ldlayer 0, layer_57C7 +ldlayer 1, layer_57DF +end + +.layer layer_57C7 +instr FONT00_INSTR_DING +transpose 12 +releaserate 225 +notepan 54 +notedv PITCH_BF3, 0xC, 73 +notedv PITCH_C4, 0xC, 73 +notedv PITCH_D4, 0xC, 73 +notedv PITCH_EF4, 0xC, 73 +notedv PITCH_F4, 0x18, 73 +end + +.layer layer_57DF +instr FONT00_INSTR_DING +transpose 24 +env envelope_65D8, 245 +notepan 74 +portamento 0x81, 20, 255 +notedv PITCH_F3, 0x18, 73 +ldelay 0x4 +notedv PITCH_F3, 0x18, 73 +end + +.channel system_menu_close +instr FONTANY_INSTR_SAWTOOTH +env envelope_6660 +releaserate 240 +ldlayer 0, layer_5804 +ldlayer 1, layer_581C +end + +.layer layer_5804 +instr FONT00_INSTR_DING +releaserate 225 +transpose 12 +notepan 54 +notedv PITCH_F4, 0x4, 73 +notedv PITCH_EF4, 0x4, 73 +notedv PITCH_D4, 0x4, 73 +notedv PITCH_C4, 0x4, 73 +notedv PITCH_BF3, 0xC, 73 +end + +.layer layer_581C +instr FONT00_INSTR_DING +transpose 24 +env envelope_65D8, 245 +notepan 74 +portamento 0x81, 20, 255 +notedv PITCH_F3, 0xC, 73 +ldelay 0x4 +notedv PITCH_F3, 0xC, 73 +end + +.channel system_puzzle_solved +instr FONTANY_INSTR_SQUARE +env envelope_664C +releaserate 248 +ldlayer 0, layer_5841 +ldlayer 1, layer_5850 +end + +.layer layer_5841 +notepan 54 +notedv PITCH_G4, 0x18, 75 +notedv PITCH_EF4, 0x18, 75 +notedv PITCH_AF3, 0x18, 75 +notedv PITCH_AF4, 0x30, 75 +end + +.layer layer_5850 +notepan 74 +ldelay 0xC +notedv PITCH_GF4, 0x18, 75 +notedv PITCH_A3, 0x18, 75 +notedv PITCH_E4, 0x18, 75 +notedv PITCH_C5, 0x30, 75 +end + +.channel system_rupee +ldlayer 0, layer_5868 +ldlayer 1, layer_587A +end + +.layer layer_5868 +instr FONTANY_INSTR_SAWTOOTH +env envelope_6660, 250 +transpose 24 +notedv PITCH_BF4, 0x6, 80 +notedv PITCH_F4, 0x6, 80 +notedv PITCH_BF4, 0x18, 80 +end + +.layer layer_587A +instr FONT00_INSTR_RUPEE +notedv PITCH_C5, 0x24, 72 +end + +.channel system_timer_ding +ldlayer 0, layer_5884 +end + +.layer layer_5884 +instr FONTANY_INSTR_TRIANGLE +env envelope_6720, 250 +notedv PITCH_A4, 0x6, 60 +end + +.channel system_error +ldlayer 0, layer_5892 +end + +.layer layer_5892 +instr FONTANY_INSTR_SAWTOOTH +env envelope_664C, 250 +notedv PITCH_E2, 0x9, 80 +notedv PITCH_E2, 0x24, 80 +end + +.channel system_treasure_appear +instr FONTANY_INSTR_SQUARE +env envelope_664C +releaserate 250 +ldlayer 0, layer_58AD +ldlayer 1, layer_58C3 +end + +.layer layer_58AD +notedv PITCH_A4, 0xC, 70 +notedv PITCH_B4, 0xC, 70 +notedv PITCH_D5, 0xC, 70 +notedv PITCH_E5, 0xC, 70 +notedv PITCH_A5, 0x12, 70 +notedv PITCH_A5, 0x12, 40 +notedv PITCH_A5, 0x12, 15 +end + +.layer layer_58C3 +ldelay 0x6 +notepan 34 +notedv PITCH_A4, 0xC, 40 +notepan 94 +notedv PITCH_B4, 0xC, 40 +notepan 34 +notedv PITCH_D5, 0xC, 40 +notepan 94 +notedv PITCH_E5, 0xC, 40 +notepan 34 +notedv PITCH_A5, 0x12, 40 +notepan 94 +notedv PITCH_A5, 0x12, 20 +notepan 64 +notedv PITCH_A5, 0x12, 10 +end + +.channel system_item_equipped +instr FONT00_INSTR_DING +env envelope_6660 +releaserate 240 +ldlayer 0, layer_58F7 +ldlayer 1, layer_590D +end + +.layer layer_58F7 +notedv PITCH_A4, 0x6, 80 +notedv PITCH_B4, 0x6, 80 +notedv PITCH_D5, 0x6, 80 +notedv PITCH_E5, 0x6, 80 +notedv PITCH_A5, 0x9, 80 +notedv PITCH_A5, 0x9, 50 +notedv PITCH_A5, 0x9, 30 +end + +.layer layer_590D +ldelay 0x6 +notepan 34 +notedv PITCH_A4, 0x6, 55 +notepan 94 +notedv PITCH_B4, 0x6, 55 +notepan 34 +notedv PITCH_D5, 0x6, 55 +notepan 94 +notedv PITCH_E5, 0x6, 55 +notepan 34 +notedv PITCH_A5, 0x9, 55 +notepan 94 +notedv PITCH_A5, 0x9, 45 +notepan 64 +notedv PITCH_A5, 0x9, 30 +end + +.channel system_cursor +ldlayer 0, layer_5937 +end + +.layer layer_5937 +instr FONTANY_INSTR_SQUARE +env envelope_6660, 242 +portamento 0x81, 36, 72 +notedv PITCH_D4, 0xA, 45 +notedv PITCH_D4, 0x6, 45 +end + +.channel system_cursor_cancel +instr FONTANY_INSTR_TRIANGLE +env envelope_664C +ldlayer 0, layer_5951 +end + +.layer layer_5951 +instr FONTANY_INSTR_TRIANGLE +env envelope_664C, 250 +notedv PITCH_A4, 0x6, 60 +notedv PITCH_E4, 0x6, 60 +notedv PITCH_D4, 0x6, 60 +notedv PITCH_B3, 0x6, 60 +notedv PITCH_A3, 0x9, 60 +notedv PITCH_B3, 0x6, 20 +notedv PITCH_A3, 0x9, 20 +end + +.channel system_heart +ldlayer 0, layer_5971 +end + +.layer layer_5971 +instr FONTANY_INSTR_SINE +env envelope_6720, 246 +portamento 0x81, 34, 127 +notedv PITCH_A3, 0x8, 100 +portamento 0x81, 46, 127 +notedv PITCH_A4, 0x8, 100 +portamento 0x81, 58, 127 +notedv PITCH_A5, 0x8, 100 +end + +.channel system_z_shift +ldlayer 0, layer_5991 +end + +.layer layer_5991 +instr FONT00_INSTR_DING +env envelope_6688, 251 +portamento 0x81, 36, 192 +notedv PITCH_A5, 0x38, 110 +end + +.channel chan_unused_599F +instr FONTANY_INSTR_SAWTOOTH +ldlayer 0, layer_59A5 +end + +.layer layer_59A5 +notedv PITCH_A4, 0x60, 105 +end + +.channel system_map_select_cursor_old +ldlayer 0, layer_59AD +end + +.layer layer_59AD +instr FONT00_INSTR_SWORD_STRIKE +env envelope_664C, 255 +transpose -5 +notedv PITCH_F4, 0x20, 105 +end + +.layer layer_unused_59B9 +instr FONT00_INSTR_SWORD_HIT_SHIELD +env envelope_66B0, 250 +legato +portamento 0x85, 46, 255 +notedv PITCH_B4, 0x12, 90 +notedv PITCH_E4, 0x8, 90 +end + +.channel system_z_cancel +ldlayer 0, layer_59CF +end + +.layer layer_59CF +instr FONTANY_INSTR_SQUARE +transpose 9 +env envelope_6660, 250 +portamento 0x81, 24, 64 +notedv PITCH_D3, 0x2, 65 +notedv PITCH_A2, 0xC, 65 +notedv PITCH_D3, 0x6, 35 +end + +.channel system_z_lock +ldlayer 0, layer_59E9 +end + +.layer layer_59E9 +instr FONT00_INSTR_DING +env envelope_6660, 250 +notedv PITCH_D4, 0x6, 90 +notedv PITCH_G4, 0x6, 90 +notedv PITCH_GF4, 0x6, 90 +notedv PITCH_G4, 0xC, 90 +notedv PITCH_G4, 0xC, 40 +notedv PITCH_G4, 0xC, 20 +end + +.channel system_menu_unused_down +ldlayer 0, layer_5A06 +end + +.layer layer_5A06 +instr FONT00_INSTR_DING +env envelope_6660, 250 +transpose 12 +notedv PITCH_GF4, 0xA, 78 +notedv PITCH_D4, 0xA, 78 +notedv PITCH_B3, 0xA, 78 +notedv PITCH_A3, 0x14, 78 +end + +.channel system_menu_unused_up +ldlayer 0, layer_5A1F +end + +.layer layer_5A1F +instr FONT00_INSTR_DING +env envelope_6660, 250 +transpose 12 +notedv PITCH_A3, 0xA, 78 +notedv PITCH_B3, 0xA, 78 +notedv PITCH_D4, 0xA, 78 +notedv PITCH_GF4, 0x14, 78 +end + +.channel system_camera_mode_toggle +ldlayer 0, layer_5A38 +end + +.layer layer_5A38 +instr FONT00_INSTR_DING +env envelope_6660, 250 +transpose 12 +notedv PITCH_D4, 0xA, 78 +notedv PITCH_A3, 0x14, 78 +end + +.channel system_minimap_toggle +ldlayer 0, layer_5A4B +end + +.layer layer_5A4B +instr FONT00_INSTR_DING +env envelope_6660, 250 +transpose 12 +notedv PITCH_A3, 0xA, 78 +notedv PITCH_D4, 0x14, 78 +end + +.channel system_z_shift_old +instr FONT00_INSTR_DING +ldlayer 0, layer_5A60 +end + +.layer layer_5A60 +notedv PITCH_EF4, 0xC, 70 +end + +.channel system_message_advance +ldlayer 0, layer_5A68 +end + +.layer layer_5A68 +instr FONT00_INSTR_DING +env envelope_6660, 248 +notedv PITCH_G4, 0x2E, 95 +end + +.channel system_countdown_caution +ldlayer 0, layer_5A76 +end + +.layer layer_5A76 +instr FONTANY_INSTR_SAWTOOTH +env envelope_6660, 250 +notedv PITCH_C4, 0x6, 60 +notedv PITCH_C4, 0x4, 40 +notedv PITCH_C4, 0x4, 20 +end + +.channel system_countdown_warn +reverb 10 +ldlayer 0, layer_5A8C +end + +.layer layer_5A8C +instr FONTANY_INSTR_SAWTOOTH +env envelope_6660, 250 +notedv PITCH_C4, 0x6, 65 +notepan 34 +notedv PITCH_C5, 0x4, 45 +notepan 94 +notedv PITCH_C5, 0x4, 45 +notepan 64 +notedv PITCH_C5, 0x4, 30 +end + +.channel system_low_health +ldlayer 0, layer_5AA9 +end + +.layer layer_5AA9 +instr FONTANY_INSTR_SAWTOOTH +env envelope_6660, 248 +notedvg PITCH_DF5, 0xD, 60, 128 +notedv PITCH_DF5, 0xD, 60 +end + +.channel system_explosive_boom +reverb 90 +ldlayer 0, layer_5AC0 +ldlayer 1, layer_5ACC +end + +.layer layer_5AC0 +instr FONT00_INSTR_EXPLOSION_0 +env envelope_6610, 251 +notepan 54 +notedv PITCH_DF4, 0x60, 107 +end + +.layer layer_5ACC +instr FONT00_INSTR_FLAME_THUNDER +env envelope_6610, 251 +notepan 54 +notedv PITCH_A1, 0x60, 104 +end + +.channel system_navi_call +ldlayer 0, layer_5ADF +ldlayer 1, layer_5AED +end + +.layer layer_5ADF +instr FONT00_INSTR_FAIRY_MAGIC +env envelope_66D0, 246 +portamento 0x81, 58, 246 +notedv PITCH_A4, 0x20, 49 +end + +.layer layer_5AED +instr FONTANY_INSTR_SINE +env envelope_6660, 248 +notedv PITCH_A5, 0x9, 50 +end + +.channel system_magic_refill +ldi 0 +stio 6 +stseq 0, layer_5B19+1 +ldlayer 0, layer_5B13 +.channel chan_5B01 +ldi 6 +call delay_varyingvol +ldio 6 +stseq 0, layer_5B19+1 +sub 255 +stio 6 +sub 50 +rbltz chan_5B01 +end + +.layer layer_5B13 +instr FONTANY_INSTR_SQUARE +releaserate 251 +notepan 34 +.layer layer_5B19 +transpose 0 +notedv PITCH_C3, 0x3, 32 +ldelay 0x3 +rjump layer_5B19 + +.channel system_z_lock_old +instr FONTANY_INSTR_SINE +ldlayer 0, layer_5B28 +end + +.layer layer_5B28 +legato +env envelope_6674, 245 +portamento 0x81, 36, 255 +notedv PITCH_F2, 0x8, 68 +portamento 0x81, 20, 225 +notedv PITCH_C4, 0x1C, 68 +end + +.channel system_unused21 +instr FONTANY_INSTR_SINE +ldlayer 0, layer_5B42 +end + +.layer layer_5B42 +ldelay 0x1 +end + +.layer layer_unused_5B45 +env envelope_6674, 245 +portamento 0x83, 32, 255 +notedv PITCH_F2, 0xC, 80 +notedv PITCH_F2, 0xC, 40 +end + +.channel system_unused22 +ldlayer 0, layer_5B58 +end + +.layer layer_5B58 +ldelay 0x1 +end + +.channel system_title_screen +instr FONTANY_INSTR_TRIANGLE +env envelope_664C +releaserate 240 +ldlayer 0, layer_5B69 +ldlayer 1, layer_5B88 +end + +.layer layer_5B69 +notepan 84 +ldelay 0x6 +notedv PITCH_G3, 0xC, 80 +notedv PITCH_C4, 0xC, 80 +notedv PITCH_G4, 0xC, 80 +notedv PITCH_C5, 0xC, 80 +env envelope_6660, 222 +notepan 44 +notedv PITCH_E5, 0x18, 30 +notepan 84 +notedv PITCH_E5, 0x18, 20 +end + +.layer layer_5B88 +notepan 44 +notedv PITCH_E3, 0xC, 80 +notedv PITCH_A3, 0xC, 80 +notedv PITCH_E4, 0xC, 80 +notedv PITCH_A4, 0xC, 80 +notepan 64 +notedv PITCH_E5, 0x60, 80 +end + +.channel system_get_item +instr FONTANY_INSTR_TRIANGLE +env envelope_664C +releaserate 240 +ldlayer 0, layer_5BA7 +end + +.layer layer_5BA7 +call layer_fn_5BB4 +.layer layer_5BAA +notedv PITCH_AF4, 0xA, 75 +notedv PITCH_AF4, 0x14, 55 +notedv PITCH_AF4, 0x14, 35 +end + +.layer layer_fn_5BB4 +notedv PITCH_AF4, 0xA, 75 +notedv PITCH_F4, 0xA, 75 +notedv PITCH_DF4, 0xA, 75 +end + +.channel system_menu_scroll_left +instr FONT00_INSTR_DING +env envelope_664C +releaserate 245 +ldlayer 0, layer_5BCC +ldlayer 1, layer_5BE1 +end + +.layer layer_5BCC +notepan 24 +.layer layer_5BCE +notedv PITCH_F4, 0x8, 70 +notedv PITCH_BF4, 0x8, 70 +notedv PITCH_A4, 0x8, 70 +notedv PITCH_G4, 0x8, 70 +notedv PITCH_F4, 0x10, 70 +notedv PITCH_F4, 0x20, 35 +end + +.layer layer_5BE1 +notedv PITCH_BF3, 0x20, 45 +notedv PITCH_A3, 0x30, 45 +end + +.channel system_menu_scroll_right +instr FONT00_INSTR_DING +env envelope_664C +releaserate 245 +ldlayer 0, layer_5BF6 +ldlayer 1, layer_5BE1 +end + +.layer layer_5BF6 +notepan 104 +rjump layer_5BCE + +.channel system_ocarina_system_error +instr FONT00_INSTR_FAIL_BELLS +env envelope_65E8 +ldlayer 0, layer_5C03 +end + +.layer layer_5C03 +notedv PITCH_G4, 0x43, 110 +end + +.channel system_camera_mode_toggle_old +ldlayer 0, layer_5C0B +end + +.layer layer_5C0B +instr FONT00_INSTR_DING +releaserate 250 +notedv PITCH_A3, 0x6, 90 +env envelope_6674, 245 +portamento 0x81, 36, 144 +notedv PITCH_A4, 0x18, 90 +end + +.channel system_minimap_toggle_old +ldlayer 0, layer_5C22 +end + +.layer layer_5C22 +instr FONT00_INSTR_DING +releaserate 250 +notedv PITCH_A4, 0x6, 90 +env envelope_6674, 245 +portamento 0x82, 36, 144 +notedv PITCH_E4, 0x18, 60 +end + +.channel system_lens_on +instr FONT00_INSTR_EYE_OF_TRUTH +env envelope_65D8 +ldlayer 0, layer_5C3E +end + +.layer layer_5C3E +legato +notedv PITCH_C4, 0x18, 100 +notedv PITCH_D4, 0x60, 100 +end + +.channel system_lens_off +instr FONT00_INSTR_EYE_OF_TRUTH +env envelope_65D8 +ldlayer 0, layer_5C4F +end + +.layer layer_5C4F +legato +notedv PITCH_C4, 0x18, 100 +notedv PITCH_BF3, 0x60, 100 +end + +.channel system_gerudo_whistle +instr FONT00_INSTR_WHISTLE +ldlayer 0, layer_5C5D +end + +.layer layer_5C5D +notedv PITCH_EF4, 0x6, 100 +notedv PITCH_F4, 0x60, 100 +end + +.channel system_minigame_bell +instr FONT00_INSTR_FAIL_BELLS +ldlayer 0, layer_5C6A +end + +.layer layer_5C6A +transpose 48 +loop 4 +releaserate 250 +notedv PITCH_C4, 0xC, 98 +releaserate 216 +notedv PITCH_C4, 0x28, 87 +loopend +end + +.channel system_message_done +instr FONT00_INSTR_DING +ldlayer 0, layer_5C80 +end + +.layer layer_5C80 +notedv PITCH_E4, 0x6, 70 +notedv PITCH_D4, 0x6, 70 +notedv PITCH_C4, 0xC, 70 +notepan 44 +notedv PITCH_C4, 0x6, 36 +notepan 84 +notedv PITCH_C4, 0xC, 36 +end + +.channel system_rupee_increase +ldlayer 0, layer_5C9B +ldlayer 1, layer_5CA1 +end + +.layer layer_5C9B +instr FONT00_INSTR_RUPEE +notedv PITCH_G5, 0xE, 66 +end + +.layer layer_5CA1 +transpose 24 +instr FONTANY_INSTR_SAWTOOTH +env envelope_6660, 250 +notedv PITCH_F4, 0x3, 52 +end + +.channel system_z_lock_enemy +ldlayer 0, layer_5CB1 +end + +.layer layer_5CB1 +instr FONT00_INSTR_Z_TARGET +transpose 48 +notedv PITCH_C4, 0x61, 100 +end + +.channel system_get_treasure_item +instr FONTANY_INSTR_TRIANGLE +env envelope_664C +releaserate 240 +ldlayer 0, layer_5CC4 +end + +.layer layer_5CC4 +call layer_fn_5BB4 +notedv PITCH_BF4, 0xA, 75 +notedv PITCH_G4, 0xA, 75 +notedv PITCH_EF4, 0xA, 75 +jump layer_5BAA + +.channel system_long_whiteout +reverb 25 +ldlayer 0, layer_5CEB +ldlayer 1, layer_5CDC +end + +.layer layer_5CDC +ldelay 0x64 +instr FONT00_INSTR_WHISTLE_PERSON +env envelope_67CC, 221 +transpose 24 +notedv PITCH_B5, 0x96, 100 +end + +.layer layer_5CEB +instr FONT00_INSTR_SLIDE_HEAVY +env envelope_67D8, 221 +transpose 12 +portamento 0x81, 2, 255 +notedv PITCH_B5, 0xFA, 85 +end + +.channel system_whiteout +reverb 25 +ldlayer 0, layer_5D12 +ldlayer 1, layer_5D05 +end + +.layer layer_5D05 +instr FONT00_INSTR_WHISTLE_PERSON +env envelope_67D8, 200 +transpose 24 +notedv PITCH_B5, 0xC8, 100 +end + +.layer layer_5D12 +instr FONT00_INSTR_SLIDE_HEAVY +env envelope_67D8, 200 +transpose 12 +notedv PITCH_B5, 0xC8, 85 +end + +.channel system_warp_in +reverb 25 +ldlayer 0, layer_5D28 +ldlayer 1, layer_5D34 +end + +.layer layer_5D28 +instr FONT00_INSTR_WARP +env envelope_6638, 221 +transpose 24 +notedv PITCH_B5, 0x40, 95 +end + +.layer layer_5D34 +instr FONT00_INSTR_DISTORTION +env envelope_66D0, 224 +transpose 12 +notedv PITCH_B5, 0x20, 65 +end + +.channel system_shotgun +instr FONT00_INSTR_SLAM_GUNSHOT +gain 25 +ldlayer 0, layer_5D4B +ldlayer 1, layer_5D51 +end + +.layer layer_5D4B +ldelay 0x2A +env envelope_66A0, 251 + +.layer layer_5D51 +transpose 48 +notedv PITCH_C4, 0x0, 115 +end + +.channel system_metronome +ldlayer 0, layer_5D5B +end + +.layer layer_5D5B +instr FONTANY_INSTR_DRUM +notedv FONT00_DRUM_TAMBO_H, 0x48, 70 +end + +.channel system_z_shift_threat +instr FONT00_INSTR_Z_TARGET +ldlayer 0, layer_5D67 +end + +.layer layer_5D67 +notedv PITCH_C4, 0x39, 110 +end + +.channel system_metronome2 +instr FONTANY_INSTR_DRUM +ldlayer 0, layer_5D71 +end + +.layer layer_5D71 +notedv FONT00_DRUM_TAMBO, 0x48, 70 +rjump layer_5D71 + +.channel system_file_cursor +ldlayer 0, layer_5D84 +ldlayer 1, layer_5D7D +end + +.layer layer_5D7D +call layer_fn_5D95 +notedv PITCH_C3, 0x10, 100 +end + +.layer layer_5D84 +call layer_fn_5D8E +notedv PITCH_C3, 0x8, 46 +notedv PITCH_C4, 0x1C, 36 +end + +.layer layer_fn_5D8E +instr FONTANY_INSTR_SINE +env envelope_664C, 251 +end + +.layer layer_fn_5D95 +instr FONT00_INSTR_WARP +env envelope_667C, 232 +transpose 36 +end + +.channel system_file_select +ldlayer 0, layer_5DA5 +ldlayer 1, layer_5DB1 +end + +.layer layer_5DA5 +instr FONT00_INSTR_WARP +env envelope_6610, 232 +transpose 36 +notedv PITCH_E3, 0x1E, 95 +end + +.layer layer_5DB1 +call layer_fn_5D8E +notedv PITCH_D4, 0x6, 50 +notedv PITCH_E4, 0x18, 50 +end + +.channel system_file_enter +ldlayer 0, layer_5DC2 +ldlayer 1, layer_5DCE +end + +.layer layer_5DC2 +transpose 36 +.layer layer_5DC4 +instr FONT00_INSTR_WARP +env envelope_6610, 232 +notedv PITCH_A3, 0x60, 112 +end + +.layer layer_5DCE +call layer_fn_5D8E +notedv PITCH_D4, 0x6, 50 +notedv PITCH_G4, 0x6, 50 +notedv PITCH_A4, 0x18, 50 +end + +.channel system_file_cancel +ldlayer 0, layer_5DE2 +ldlayer 1, layer_5DE6 +end + +.layer layer_5DE2 +transpose 24 +rjump layer_5DC4 + +.layer layer_5DE6 +call layer_fn_5D8E +notedv PITCH_A4, 0x6, 50 +notedv PITCH_E4, 0x6, 50 +notedv PITCH_A3, 0x18, 50 +end + +.channel system_file_error +ldlayer 0, layer_5DF7 +end + +.layer layer_5DF7 +instr FONTANY_INSTR_SINE +env envelope_6718, 240 +notedv PITCH_BF2, 0x9, 70 +notedv PITCH_A2, 0x9, 70 +notedv PITCH_BF2, 0x9, 70 +notedv PITCH_A2, 0x18, 70 +end + +.channel system_equip_fire +ldlayer 0, layer_1438 +ldlayer 1, layer_B1D +ldlayer 2, layer_A6E +end + +.channel system_equip_ice +ldlayer 0, layer_1438 +ldlayer 1, layer_B47 +ldlayer 2, layer_B41 +end + +.channel system_equip_light +ldlayer 0, layer_1438 +ldlayer 1, layer_B6D +ldlayer 2, layer_B67 +end + +.channel system_equip_magic_bow +ldlayer 0, layer_5E2C +end + +.layer layer_5E2C +transpose 12 +jump layer_1438 + +.channel system_metronome3 +ldlayer 0, layer_5E35 +end + +.layer layer_5E35 +instr FONTANY_INSTR_DRUM +releaserate 150 +notedv FONT00_DRUM_TAMBO_H, 0x24, 70 +end + +.channel system_skulltula_token_appears +instr FONT00_INSTR_DING +env envelope_6660 +releaserate 250 +ldlayer 0, layer_5E51 +ldlayer 1, layer_5E4B +end + +.layer layer_5E4B +ldelay 0x5 +notepan 94 +rjump layer_5E53 + +.layer layer_5E51 +notepan 34 +.layer layer_5E53 +transpose 12 +notedv PITCH_F4, 0xC, 85 +notedv PITCH_BF4, 0xC, 85 +notedv PITCH_EF5, 0xC, 85 +notedv PITCH_BF5, 0xC, 85 +notedv PITCH_F5, 0x18, 85 +notedv PITCH_F5, 0x18, 45 +notedv PITCH_F5, 0x18, 25 +end + +.channel system_silver_rupee +ldlayer 0, layer_5E6F +end + +.layer layer_5E6F +instr FONTANY_INSTR_SINE +env envelope_66D0, 248 +notedv PITCH_BF3, 0xC, 80 +notedv PITCH_F3, 0xC, 80 +notedv PITCH_D4, 0xC, 80 +notedv PITCH_EF4, 0xC, 80 +notedv PITCH_F4, 0x18, 80 +notedv PITCH_F4, 0x18, 40 +end + +.channel system_carrot_recovered +ldlayer 0, layer_5E8C +end + +.layer layer_5E8C +instr FONTANY_INSTR_SINE +env envelope_6720, 246 +portamento 0x83, 32, 127 +notedv PITCH_C4, 0x8, 80 +notedv PITCH_C5, 0xC, 80 +end diff --git a/assets/sequences/sfxbanks/voice.seq.inc b/assets/sequences/sfxbanks/voice.seq.inc new file mode 100644 index 00000000000..8fb43c47fbd --- /dev/null +++ b/assets/sequences/sfxbanks/voice.seq.inc @@ -0,0 +1,1083 @@ +.table table_voice +entry voice_link_adult_attack +entry voice_link_adult_attack_long +entry voice_link_adult_epona +entry voice_link_adult_ledge_grab +entry voice_link_adult_ledge_climb +entry voice_link_adult_hurt +entry voice_link_adult_frozen +entry voice_link_adult_fall_short +entry voice_link_adult_fall_long +entry voice_link_adult_low_health +entry voice_link_adult_drink_gasp +entry voice_link_adult_death +entry voice_link_adult_wallmaster +entry voice_link_adult_grabbed +entry voice_link_adult_sneeze +entry voice_link_adult_sweat +entry voice_link_adult_drink +entry voice_link_adult_idle +entry voice_link_adult_sword_swing_unused +entry voice_link_child_shiver +entry voice_link_adult_jump +entry voice_link_adult_cast_spell1 +entry voice_link_adult_shock +entry voice_link_adult_cast_spell2 +entry voice_link_adult_push_block +entry voice_link_adult_hookshot_hang +entry voice_link_adult_knockback +entry voice_link_adult_unused +entry voice_link_adult_cast_spell3 +entry voice_link_adult_fall_long +entry voice_link_adult_knockback_unused +entry voice_link_adult_attack +entry voice_link_child_attack +entry voice_link_child_attack_long +entry voice_link_adult_epona +entry voice_link_child_ledge_grab +entry voice_link_child_ledge_climb +entry voice_link_child_hurt +entry voice_link_child_frozen +entry voice_link_child_fall_short +entry voice_link_child_fall_long +entry voice_link_child_low_health +entry voice_link_child_drink_gasp +entry voice_link_child_death +entry voice_link_child_wallmaster +entry voice_link_child_grabbed +entry voice_link_child_sneeze +entry voice_link_child_sweat +entry voice_link_child_drink +entry voice_link_child_idle +entry voice_link_child_sword_swing_unused +entry voice_link_child_shiver +entry voice_link_child_jump +entry voice_link_child_cast_spell1 +entry voice_link_child_shock +entry voice_link_child_cast_spell2 +entry voice_link_child_push_block +entry voice_link_child_hookshot_hang +entry voice_link_child_knockback +entry voice_link_child_unused +entry voice_link_child_cast_spell3 +entry voice_link_child_fall_long +entry voice_link_child_cutscene_attacked +entry voice_link_adult_attack +entry voice_navi_unused +entry voice_navi_unused +entry voice_navi_unused +entry voice_navi_target +entry voice_navi_greeting +entry voice_navi_target +entry voice_navi_target +entry voice_navi_target +entry voice_navi_target +entry voice_navi_target +entry voice_navi_target +entry voice_navi_target +entry voice_navi_target +entry voice_navi_target +entry voice_navi_target +entry voice_navi_target +entry voice_npcs +entry voice_npcs +entry voice_npcs +entry voice_npcs +entry voice_npcs +entry voice_npcs +entry voice_npcs +entry voice_npcs +entry voice_npcs +entry voice_npcs +entry voice_npcs +entry voice_npcs +entry voice_npcs +entry voice_npcs +entry voice_npcs +entry voice_npcs +entry voice_npcs +entry voice_npcs +entry voice_npcs +entry voice_npcs +entry voice_npcs +entry voice_npcs +entry voice_npcs +entry voice_npcs +entry voice_npcs +entry voice_npcs +entry voice_npcs +entry voice_npcs +entry voice_npcs +entry voice_npcs +entry voice_npcs +entry voice_npcs +entry voice_npcs +entry voice_npcs +entry voice_npcs +entry voice_npcs +entry voice_npcs +entry voice_npcs +entry voice_npcs +entry voice_other_npcs +entry voice_other_npcs +entry voice_other_npcs +entry voice_other_npcs +entry voice_other_npcs +entry voice_other_npcs +entry voice_npcs +entry voice_npcs +entry voice_npcs + +# Play a random voice clip, but not two equal in a row. +.channel play_random_voice +stseq 0, getrand+1 +stseq 0, random_voice_cmpmax_instr+1 +ldi 0 +stseq 0, layer_play_voice+1 # overwrite delay = 0 +call getrand +subio 6 +rbeqz random_voice_same +call getrand +rjump random_voice_store_last +.channel random_voice_same +call getrand +sub 255 +stio 6 +.channel random_voice_cmpmax_instr +sub 0 +rbeqz random_voice_store_last +ldio 6 +.channel random_voice_store_last +# Store the last index for both channel 14 and 15 +stcio 14, 6 +stcio 15, 6 +.channel play_voice_readtone_instr +ldseq addr_616D # read tone at index. source gets overwritten by caller +stseq 64, layer_play_voice # overwrite "notedv tone" +ldio 6 +.channel play_voice_readvelocity_instr +ldseq addr_6171 # read velocity (~volume) at index. source gets overwritten by caller +.channel play_voice_with_velocity +stseq 0, layer_play_voice+2 # overwrite velocity +ldlayer 0, layer_play_voice + +.channel voice_navi_unused +end + +.layer layer_play_voice +notedv PITCH_A0, 0x0, 127 +end + +.channel getrand +rand 0 +end + +.channel play_dynamic_voice +stio 6 +ldi 0 +stseq 0, layer_play_voice+1 # overwrite delay = 0 +ldio 6 +rjump play_voice_readtone_instr + +.channel play_single_voice +ldi 0 +stseq 0, layer_play_voice+1 # overwrite delay = 0 +ptrtodyntbl +ldi 0 +dyntblv # read tone from large[0] +stseq 64, layer_play_voice # overwrite "notedv tone" +ldi 1 +dyntblv # read velocity from large[1] +rjump play_voice_with_velocity + +# Same as play_random_voice but only supports two voice clips. +.channel play_alternating_voice +stseq 0, layer_play_voice+1 # overwrite delay = argument +ldio 6 +sub 255 +and 1 +stio 6 +rjump play_voice_readtone_instr + +.channel voice_link_adult_attack +ldptr addr_616D +stptrtoseq play_voice_readtone_instr+1 +ldptr addr_6171 +stptrtoseq play_voice_readvelocity_instr+1 +ldi 4 +rjump play_random_voice + +.array addr_616D +byte FONT00_EFFECT_LINK_ADULT_ATTACK_0 +byte FONT00_EFFECT_LINK_ADULT_ATTACK_1 +byte FONT00_EFFECT_LINK_ADULT_ATTACK_2 +byte FONT00_EFFECT_LINK_ADULT_ATTACK_3 + +.array addr_6171 +byte 105 +byte 105 +byte 105 +byte 105 + +.channel voice_link_adult_attack_long +ldptr addr_6197 +stptrtoseq play_voice_readtone_instr+1 +ldptr addr_6199 +stptrtoseq play_voice_readvelocity_instr+1 +rand 2 +rjump play_dynamic_voice + +.channel chan_unused_6185 +subio 6 +rbeqz chan_618C +rand 2 +rjump chan_6196 +.channel chan_618C +rand 2 +sub 255 +stio 6 +sub 2 +rbeqz chan_6196 +ldio 6 +.channel chan_6196 +stio 6 + +.array addr_6197 +byte FONT00_EFFECT_LINK_ADULT_MAJOR_0 +byte FONT00_EFFECT_LINK_ADULT_MAJOR_1 + +.array addr_6199 +byte 110 +byte 110 + +.channel voice_link_adult_epona +ldptr addr_61BD +stptrtoseq play_voice_readtone_instr+1 +ldptr addr_61BF +stptrtoseq play_voice_readvelocity_instr+1 +rand 2 +rjump play_dynamic_voice + +.channel chan_unused_61AB +subio 6 +rbeqz chan_61B2 +rand 2 +rjump chan_61BC +.channel chan_61B2 +rand 2 +sub 255 +stio 6 +sub 2 +rbeqz chan_61BC +ldio 6 +.channel chan_61BC +stio 6 + +.array addr_61BD +byte FONT00_EFFECT_LINK_ADULT_SPUR_0 +byte FONT00_EFFECT_LINK_ADULT_SPUR_1 + +.array addr_61BF +byte 105 +byte 105 + +.channel voice_link_adult_ledge_grab +ldptr addr_61D1 +stptrtoseq play_voice_readtone_instr+1 +ldptr addr_61D3 +stptrtoseq play_voice_readvelocity_instr+1 +ldi 0 +rjump play_alternating_voice + +.array addr_61D1 +byte FONT00_EFFECT_LINK_ADULT_LEDGE_0 +byte FONT00_EFFECT_LINK_ADULT_LEDGE_2 + +.array addr_61D3 +byte 95 +byte 105 + +.channel voice_link_adult_ledge_climb +ldptr addr_61E6 +stptrtoseq play_voice_readtone_instr+1 +ldptr addr_61E8 +stptrtoseq play_voice_readvelocity_instr+1 +rand 2 +jump play_dynamic_voice + +.array addr_61E6 +byte FONT00_EFFECT_LINK_ADULT_CLIMB +byte FONT00_EFFECT_LINK_ADULT_LEDGE_1 + +.array addr_61E8 +byte 72 +byte 80 + +.channel voice_link_adult_hurt +ldptr addr_61FB +stptrtoseq play_voice_readtone_instr+1 +ldptr addr_61FE +stptrtoseq play_voice_readvelocity_instr+1 +ldi 3 +jump play_random_voice + +.array addr_61FB +byte FONT00_EFFECT_LINK_ADULT_HURT_0 +byte FONT00_EFFECT_LINK_ADULT_HURT_1 +byte FONT00_EFFECT_LINK_ADULT_HURT_2 + +.array addr_61FE +byte 117 +byte 117 +byte 117 + +.channel voice_link_adult_frozen +ldptr addr_6212 +stptrtoseq play_voice_readtone_instr+1 +ldptr addr_6215 +stptrtoseq play_voice_readvelocity_instr+1 +ldi 3 +jump play_random_voice + +.array addr_6212 +byte FONT00_EFFECT_LINK_ADULT_HURT_3 +byte FONT00_EFFECT_LINK_ADULT_KNOCKBACK +byte FONT00_EFFECT_LINK_ADULT_HURT_4 + +.array addr_6215 +byte 113 +byte 113 +byte 113 + +.channel voice_link_adult_fall_short +ldptr addr_6229 +stptrtoseq play_voice_readtone_instr+1 +ldptr addr_622B +stptrtoseq play_voice_readvelocity_instr+1 +rand 2 +jump play_dynamic_voice + +.array addr_6229 +byte FONT00_EFFECT_LINK_ADULT_GASP_0 +byte FONT00_EFFECT_LINK_ADULT_GASP_1 + +.array addr_622B +byte 100 +byte 100 + +.channel voice_link_adult_fall_long +ldptr addr_623E +stptrtoseq play_voice_readtone_instr+1 +ldptr addr_6240 +stptrtoseq play_voice_readvelocity_instr+1 +rand 2 +jump play_dynamic_voice + +.array addr_623E +byte FONT00_EFFECT_LINK_ADULT_FALL_0 +byte FONT00_EFFECT_LINK_ADULT_FALL_1 + +.array addr_6240 +byte 110 +byte 110 + +.channel voice_link_adult_low_health +ldptr addr_6253 +stptrtoseq play_voice_readtone_instr+1 +ldptr addr_6255 +stptrtoseq play_voice_readvelocity_instr+1 +rand 2 +jump play_dynamic_voice + +.array addr_6253 +byte FONT00_EFFECT_LINK_ADULT_PANT_0 +byte FONT00_EFFECT_LINK_ADULT_PANT_1 + +.array addr_6255 +byte 90 +byte 90 + +.channel voice_link_adult_drink_gasp +ldlayer 0, layer_625B +end + +.layer layer_625B +notedv PITCH_F5, 0x0, 96 +end + +.channel voice_link_adult_death +ldlayer 0, layer_6263 +end + +.layer layer_6263 +transpose 1 +notedv PITCH_BF1, 0x57, 100 +notedv PITCH_B1, 0x61, 100 +notedv PITCH_C2, 0x47, 100 +end + +.channel voice_link_adult_wallmaster +ldptr addr_6280 +stptrtoseq play_voice_readtone_instr+1 +ldptr addr_6282 +stptrtoseq play_voice_readvelocity_instr+1 +rand 2 +jump play_dynamic_voice + +.array addr_6280 +byte FONT00_EFFECT_LINK_ADULT_FALL_0 +byte FONT00_EFFECT_LINK_ADULT_FALL_1 + +.array addr_6282 +byte 105 +byte 105 + +.channel voice_link_adult_grabbed +jump voice_link_adult_hurt + +.channel voice_link_adult_sneeze +ldlayer 0, layer_628B +end + +.layer layer_628B +transpose 1 +notedv PITCH_DF2, 0x7F, 100 +notedv PITCH_D2, 0x118, 100 +notedv PITCH_EF2, 0x13E, 100 +end + +.channel voice_link_adult_sweat +ldlayer 0, layer_629D +end + +.layer layer_629D +transpose 1 +notedv PITCH_E2, 0x122, 100 +notedv PITCH_F2, 0xA3, 100 +notedv PITCH_GF2, 0x35, 100 +end + +.channel voice_link_adult_drink +ldlayer 0, layer_62AF +end + +.layer layer_62AF +notedv PITCH_E5, 0x50, 80 +rjump layer_62AF + +.channel voice_link_adult_idle +ldlayer 0, layer_62B8 +end + +.layer layer_62B8 +transpose 1 +notedv PITCH_G2, 0xB9, 100 +notedv PITCH_AF2, 0x86, 100 +notedv PITCH_A2, 0x74, 100 +end + +.channel voice_link_adult_sword_swing_unused +ldptr addr_62CC +jump play_single_voice + +.array addr_62CC +byte FONT00_EFFECT_LINK_ADULT_ATTACK_0 +byte 100 + +.channel voice_link_adult_jump +ldio 6 +sub 255 +stio 6 +and 1 +ldseq addr_62E8 +stseq 64, layer_64BF +rand 2 +ldseq addr_62EA +stseq 0, layer_64BF+2 +ldlayer 0, layer_64BF +end + +.array addr_62E8 +byte FONT00_EFFECT_LINK_ADULT_JUMP +byte FONT00_EFFECT_LINK_ADULT_GASP_2 + +.array addr_62EA +byte 80 +byte 85 + +.channel voice_link_adult_cast_spell1 +ldptr addr_62F2 +jump play_single_voice + +.array addr_62F2 +byte FONT00_EFFECT_LINK_ADULT_MAJOR_1 +byte 110 + +.channel voice_link_adult_shock +ldlayer 0, layer_62F8 +end + +.layer layer_62F8 +transpose 2 +notedv PITCH_EF1, 0x0, 85 +end + +.channel voice_link_adult_cast_spell2 +ldptr addr_6304 +jump play_single_voice + +.array addr_6304 +byte FONT00_EFFECT_LINK_ADULT_MAJOR_0 +byte 95 + +.channel voice_link_adult_push_block +ldptr addr_630C +jump play_single_voice + +.array addr_630C +byte FONT00_EFFECT_LINK_ADULT_CLIMB +byte 82 + +.channel voice_link_adult_hookshot_hang +ldptr addr_6314 +jump play_single_voice + +.array addr_6314 +byte FONT00_EFFECT_LINK_ADULT_LEDGE_0 +byte 95 + +.channel voice_link_adult_knockback +ldptr addr_631C +jump play_single_voice + +.array addr_631C +byte FONT00_EFFECT_LINK_ADULT_FALL_DMG +byte 110 + +.channel voice_link_adult_unused +ldptr addr_6324 +jump play_single_voice + +.array addr_6324 +byte FONT00_EFFECT_LINK_ADULT_LIFT +byte 100 + +.channel voice_link_adult_cast_spell3 +ldptr addr_632C +jump play_single_voice + +.array addr_632C +byte FONT00_EFFECT_LINK_ADULT_SPELL +byte 110 + +.channel voice_link_adult_knockback_unused +ldptr addr_6334 +jump play_single_voice + +.array addr_6334 +byte FONT00_EFFECT_LINK_ADULT_KNOCKBACK +byte 113 + +.channel voice_link_child_attack +ldptr addr_6347 +stptrtoseq play_voice_readtone_instr+1 +ldptr addr_634B +stptrtoseq play_voice_readvelocity_instr+1 +ldi 4 +jump play_random_voice + +.array addr_6347 +byte FONT00_EFFECT_LINK_CHILD_ATTACK_0 +byte FONT00_EFFECT_LINK_CHILD_ATTACK_1 +byte FONT00_EFFECT_LINK_CHILD_ATTACK_2 +byte FONT00_EFFECT_LINK_CHILD_ATTACK_3 + +.array addr_634B +byte 110 +byte 110 +byte 110 +byte 110 + +.channel voice_link_child_attack_long +ldptr addr_6372 +stptrtoseq play_voice_readtone_instr+1 +ldptr addr_6374 +stptrtoseq play_voice_readvelocity_instr+1 +rand 2 +jump play_dynamic_voice + +.channel chan_unused_6360 +subio 6 +rbeqz chan_6367 +rand 2 +rjump chan_6371 +.channel chan_6367 +rand 2 +sub 255 +stio 6 +sub 2 +rbeqz chan_6371 +ldio 6 +.channel chan_6371 +stio 6 + +.array addr_6372 +byte FONT00_EFFECT_LINK_CHILD_STRONG_0 +byte FONT00_EFFECT_LINK_CHILD_STRONG_1 + +.array addr_6374 +byte 110 +byte 110 + +.channel voice_link_child_ledge_grab +ldio 6 +sub 255 +stio 6 +and 1 +ldseq addr_6396 +stseq 64, layer_6390 +rand 2 +ldseq addr_6398 +stseq 0, layer_6390+2 +ldlayer 0, layer_6390 +end + +.layer layer_6390 +notedv PITCH_A0, 0x0, 100 +ldelay 0x30 +end + +.array addr_6396 +byte FONT00_EFFECT_LINK_CHILD_LEDGE_0 +byte FONT00_EFFECT_LINK_CHILD_LEDGE_1 + +.array addr_6398 +byte 100 +byte 100 + +.channel voice_link_child_ledge_climb +ldptr addr_63AB +stptrtoseq play_voice_readtone_instr+1 +ldptr addr_63AD +stptrtoseq play_voice_readvelocity_instr+1 +rand 2 +jump play_dynamic_voice + +.array addr_63AB +byte FONT00_EFFECT_LINK_CHILD_SIGH_0 +byte FONT00_EFFECT_LINK_CHILD_SIGH_1 + +.array addr_63AD +byte 90 +byte 70 + +.channel voice_link_child_hurt +ldptr addr_63C0 +stptrtoseq play_voice_readtone_instr+1 +ldptr addr_63C3 +stptrtoseq play_voice_readvelocity_instr+1 +ldi 3 +jump play_random_voice + +.array addr_63C0 +byte FONT00_EFFECT_LINK_CHILD_HURT_0 +byte FONT00_EFFECT_LINK_CHILD_HURT_1 +byte FONT00_EFFECT_LINK_CHILD_HURT_2 + +.array addr_63C3 +byte 110 +byte 110 +byte 110 + +.channel voice_link_child_frozen +ldptr addr_63D7 +stptrtoseq play_voice_readtone_instr+1 +ldptr addr_63DA +stptrtoseq play_voice_readvelocity_instr+1 +ldi 3 +jump play_random_voice + +.array addr_63D7 +byte FONT00_EFFECT_LINK_CHILD_HURT_3 +byte FONT00_EFFECT_LINK_CHILD_KNOCKBACK +byte FONT00_EFFECT_LINK_CHILD_HURT_4 + +.array addr_63DA +byte 110 +byte 110 +byte 110 + +.channel voice_link_child_fall_short +ldptr addr_63EE +stptrtoseq play_voice_readtone_instr+1 +ldptr addr_63F0 +stptrtoseq play_voice_readvelocity_instr+1 +rand 2 +jump play_dynamic_voice + +.array addr_63EE +byte FONT00_EFFECT_LINK_CHILD_GASP_0 +byte FONT00_EFFECT_LINK_CHILD_GASP_1 + +.array addr_63F0 +byte 100 +byte 100 + +.channel voice_link_child_fall_long +ldptr addr_6403 +stptrtoseq play_voice_readtone_instr+1 +ldptr addr_6405 +stptrtoseq play_voice_readvelocity_instr+1 +rand 2 +jump play_dynamic_voice + +.array addr_6403 +byte FONT00_EFFECT_LINK_CHILD_FALL_0 +byte FONT00_EFFECT_LINK_CHILD_FALL_1 + +.array addr_6405 +byte 100 +byte 100 + +.channel voice_link_child_low_health +ldptr addr_6418 +stptrtoseq play_voice_readtone_instr+1 +ldptr addr_641A +stptrtoseq play_voice_readvelocity_instr+1 +rand 2 +jump play_dynamic_voice + +.array addr_6418 +byte FONT00_EFFECT_LINK_CHILD_WHEEZE +byte FONT00_EFFECT_LINK_CHILD_PANT + +.array addr_641A +byte 85 +byte 85 + +.channel voice_link_child_drink_gasp +ldlayer 0, layer_6420 +end + +.layer layer_6420 +notedv PITCH_DF5, 0x0, 96 +end + +.channel voice_link_child_death +ldlayer 0, layer_6428 +end + +.layer layer_6428 +transpose 1 +notedv PITCH_A0, 0x62, 100 +notedv PITCH_BF0, 0x6A, 100 +notedv PITCH_B0, 0x3A, 100 +end + +.channel voice_link_child_wallmaster +ldptr addr_6445 +stptrtoseq play_voice_readtone_instr+1 +ldptr addr_6447 +stptrtoseq play_voice_readvelocity_instr+1 +rand 2 +jump play_dynamic_voice + +.array addr_6445 +byte FONT00_EFFECT_LINK_CHILD_FALL_0 +byte FONT00_EFFECT_LINK_CHILD_FALL_1 + +.array addr_6447 +byte 100 +byte 100 + +.channel voice_link_child_grabbed +ldptr addr_644F +jump play_single_voice + +.array addr_644F +byte FONT00_EFFECT_LINK_CHILD_DEATH_0 +byte 100 + +.channel voice_link_child_sneeze +ldlayer 0, layer_6455 +end + +.layer layer_6455 +transpose 1 +notedv PITCH_C1, 0x10B, 50 +notedv PITCH_C1, 0xC5, 50 +notedv PITCH_D1, 0x87, 100 +notedv PITCH_EF1, 0x21, 100 +end + +.channel voice_link_child_sweat +ldlayer 0, layer_646B +end + +.layer layer_646B +transpose 1 +notedv PITCH_E1, 0xD9, 100 +notedv PITCH_F1, 0x62, 100 +notedv PITCH_GF1, 0x109, 100 +end + +.channel voice_link_child_drink +ldlayer 0, layer_647D +end + +.layer layer_647D +notedv PITCH_C5, 0x50, 80 +rjump layer_647D + +.channel voice_link_child_idle +ldlayer 0, layer_6486 +end + +.layer layer_6486 +transpose 1 +notedv PITCH_G1, 0x41, 100 +notedv PITCH_AF1, 0x10A, 100 +notedv PITCH_A1, 0x53, 100 +end + +.channel voice_link_child_sword_swing_unused +ldptr addr_6499 +jump play_single_voice + +.array addr_6499 +byte FONT00_EFFECT_LINK_CHILD_ATTACK_0 +byte 100 + +.channel voice_link_child_shiver +ldlayer 0, layer_649F +end + +.layer layer_649F +transpose 1 +notedv PITCH_C1, 0x0, 50 +end + +.channel voice_link_child_jump +ldio 6 +sub 255 +stio 6 +and 1 +ldseq addr_64C5 +stseq 64, layer_64BF +rand 2 +ldseq addr_64C7 +stseq 0, layer_64BF+2 +ldlayer 0, layer_64BF +end + +.layer layer_64BF +notedv PITCH_A0, 0x0, 100 +ldelay 0x30 +end + +.array addr_64C5 +byte FONT00_EFFECT_LINK_CHILD_JUMP_0 +byte FONT00_EFFECT_LINK_ADULT_JUMP_1 + +.array addr_64C7 +byte 80 +byte 80 + +.channel voice_link_child_cast_spell1 +ldptr addr_64CF +jump play_single_voice + +.array addr_64CF +byte FONT00_EFFECT_LINK_CHILD_STRONG_1 +byte 110 + +.channel voice_link_child_shock +ldlayer 0, layer_64D5 +end + +.layer layer_64D5 +transpose 2 +notedv PITCH_E1, 0x0, 85 +end + +.channel voice_link_child_cast_spell2 +ldptr addr_64E1 +jump play_single_voice + +.array addr_64E1 +byte FONT00_EFFECT_LINK_CHILD_STRONG_0 +byte 95 + +.channel voice_link_child_push_block +ldptr addr_64E9 +jump play_single_voice + +.array addr_64E9 +byte FONT00_EFFECT_LINK_CHILD_SIGH_0 +byte 90 + +.channel voice_link_child_hookshot_hang +ldptr addr_64F1 +jump play_single_voice + +.array addr_64F1 +byte FONT00_EFFECT_LINK_CHILD_LEDGE_0 +byte 100 + +.channel voice_link_child_knockback +ldptr addr_64F9 +jump play_single_voice + +.array addr_64F9 +byte FONT00_EFFECT_LINK_CHILD_FALL_DMG +byte 115 + +.channel voice_link_child_unused +ldptr addr_6501 +jump play_single_voice + +.array addr_6501 +byte FONT00_EFFECT_LINK_CHILD_CHARGE +byte 100 + +.channel voice_link_child_cast_spell3 +ldptr addr_6509 +jump play_single_voice + +.array addr_6509 +byte FONT00_EFFECT_LINK_CHILD_SPELL +byte 110 + +.channel voice_link_child_cutscene_attacked +ldptr addr_6511 +jump play_single_voice + +.array addr_6511 +byte FONT00_EFFECT_LINK_CHILD_FALL_1 +byte 100 + +.channel voice_navi_greeting +ldi 32 +stio 1 +ldlayer 0, layer_651A +end + +.layer layer_651A +transpose 2 +notedv PITCH_DF1, 0x0, 100 +end + +.channel voice_npcs +ldio 4 +sub 80 +stseq 25, layer_6536 # set semitone = sound id - 80 + 25 +ldseq addr_653B +stseq 0, layer_6536+2 +ldlayer 0, layer_6534 +panweight 96 +end + +.layer layer_6534 +transpose 1 +.layer layer_6536 +notedvg 33, 0x0, 100, 0 +end + +.array addr_653B +byte 100 +byte 100 +byte 100 +byte 100 +byte 100 +byte 100 +byte 100 +byte 100 +byte 110 +byte 100 +byte 100 +byte 100 +byte 100 +byte 100 +byte 100 +byte 100 +byte 100 +byte 100 +byte 100 +byte 100 +byte 100 +byte 100 +byte 100 +byte 100 +byte 100 +byte 100 +byte 100 +byte 100 +byte 100 +byte 100 +byte 100 +byte 100 +byte 100 +byte 100 +byte 100 +byte 100 +byte 100 +byte 100 +byte 110 + +.channel voice_other_npcs +ldio 4 +sub 119 +stseq 0, layer_6576 # set semitone = sound id - 119 +ldseq addr_657B +stseq 0, layer_6576+2 +ldlayer 0, layer_6574 +end + +.layer layer_6574 +transpose 2 +.layer layer_6576 +notedvg 0, 0x0, 100, 0 +end + +.array addr_657B +byte 100 +byte 100 +byte 100 +byte 100 +byte 100 +byte 100 + +.channel voice_navi_target +ldi 32 +stio 1 +ldlayer 1, layer_6598 +ldptr addr_65A7 +stptrtoseq play_voice_readtone_instr+1 +ldptr addr_65AA +stptrtoseq play_voice_readvelocity_instr+1 +ldi 3 +jump play_random_voice + +.layer layer_6598 +instr FONT00_INSTR_FAIRY_MAGIC +env envelope_66B8, 251 +legato +portamento 0x81, 51, 255 +notedv PITCH_F5, 0x30, 65 +end + +.array addr_65A7 +byte FONT00_EFFECT_NAVI_WATCH_OUT +byte FONT00_EFFECT_NAVI_LOOK +byte FONT00_EFFECT_NAVI_HEY + +.array addr_65AA +byte 100 +byte 95 +byte 105 + +.filter filter_voice0 +filter 0, 0, 0, 0, 0, 0, 0, 0 + +.filter filter_voice1 +filter 0, 0, 0, 0, 0, 0, 0, 0 diff --git a/assets/xml/samples/0 Sound Effects.xml b/assets/xml/samples/0 Sound Effects.xml new file mode 100644 index 00000000000..da1f12fad5f --- /dev/null +++ b/assets/xml/samples/0 Sound Effects.xml @@ -0,0 +1,1052 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/xml/samples/1 Orchestra.xml b/assets/xml/samples/1 Orchestra.xml new file mode 100644 index 00000000000..35d5b06b4c3 --- /dev/null +++ b/assets/xml/samples/1 Orchestra.xml @@ -0,0 +1,257 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/xml/samples/2 Inside the Deku Tree.xml b/assets/xml/samples/2 Inside the Deku Tree.xml new file mode 100644 index 00000000000..dff8698a62d --- /dev/null +++ b/assets/xml/samples/2 Inside the Deku Tree.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/assets/xml/samples/3 Inside Jabu Jabu.xml b/assets/xml/samples/3 Inside Jabu Jabu.xml new file mode 100644 index 00000000000..93b5a4887dc --- /dev/null +++ b/assets/xml/samples/3 Inside Jabu Jabu.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/assets/xml/samples/4 Forest Temple (Unused).xml b/assets/xml/samples/4 Forest Temple (Unused).xml new file mode 100644 index 00000000000..8e63650d4de --- /dev/null +++ b/assets/xml/samples/4 Forest Temple (Unused).xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/assets/xml/samples/5 Goron City.xml b/assets/xml/samples/5 Goron City.xml new file mode 100644 index 00000000000..b65db087df2 --- /dev/null +++ b/assets/xml/samples/5 Goron City.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/assets/xml/samples/6 Spirit Temple.xml b/assets/xml/samples/6 Spirit Temple.xml new file mode 100644 index 00000000000..b1cfcdc57fb --- /dev/null +++ b/assets/xml/samples/6 Spirit Temple.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/xml/sequences/Sequences.xml b/assets/xml/sequences/Sequences.xml new file mode 100644 index 00000000000..fea36e05bb4 --- /dev/null +++ b/assets/xml/sequences/Sequences.xml @@ -0,0 +1,112 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/xml/soundfonts/Ambience.xml b/assets/xml/soundfonts/Ambience.xml new file mode 100644 index 00000000000..c92d4fd498d --- /dev/null +++ b/assets/xml/soundfonts/Ambience.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/xml/soundfonts/Deku Tree (Unused).xml b/assets/xml/soundfonts/Deku Tree (Unused).xml new file mode 100644 index 00000000000..3a5c98f9b17 --- /dev/null +++ b/assets/xml/soundfonts/Deku Tree (Unused).xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/assets/xml/soundfonts/Deku Tree.xml b/assets/xml/soundfonts/Deku Tree.xml new file mode 100644 index 00000000000..39673426379 --- /dev/null +++ b/assets/xml/soundfonts/Deku Tree.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/assets/xml/soundfonts/Dodongo's Cavern.xml b/assets/xml/soundfonts/Dodongo's Cavern.xml new file mode 100644 index 00000000000..2c5b4690cf6 --- /dev/null +++ b/assets/xml/soundfonts/Dodongo's Cavern.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/assets/xml/soundfonts/Ending 1.xml b/assets/xml/soundfonts/Ending 1.xml new file mode 100644 index 00000000000..4f73309fbe9 --- /dev/null +++ b/assets/xml/soundfonts/Ending 1.xml @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/xml/soundfonts/Ending 2.xml b/assets/xml/soundfonts/Ending 2.xml new file mode 100644 index 00000000000..151d774281b --- /dev/null +++ b/assets/xml/soundfonts/Ending 2.xml @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/xml/soundfonts/Fairy Fountain.xml b/assets/xml/soundfonts/Fairy Fountain.xml new file mode 100644 index 00000000000..0c2230836ea --- /dev/null +++ b/assets/xml/soundfonts/Fairy Fountain.xml @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/xml/soundfonts/Fire Temple.xml b/assets/xml/soundfonts/Fire Temple.xml new file mode 100644 index 00000000000..0f354284a32 --- /dev/null +++ b/assets/xml/soundfonts/Fire Temple.xml @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/xml/soundfonts/Forest Temple.xml b/assets/xml/soundfonts/Forest Temple.xml new file mode 100644 index 00000000000..394ed2dde5c --- /dev/null +++ b/assets/xml/soundfonts/Forest Temple.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/assets/xml/soundfonts/Game Over.xml b/assets/xml/soundfonts/Game Over.xml new file mode 100644 index 00000000000..054e4ce7528 --- /dev/null +++ b/assets/xml/soundfonts/Game Over.xml @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/xml/soundfonts/Ganon's Castle (Organ).xml b/assets/xml/soundfonts/Ganon's Castle (Organ).xml new file mode 100644 index 00000000000..630ef6487d0 --- /dev/null +++ b/assets/xml/soundfonts/Ganon's Castle (Organ).xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/assets/xml/soundfonts/Ganon's Castle.xml b/assets/xml/soundfonts/Ganon's Castle.xml new file mode 100644 index 00000000000..61879dddb60 --- /dev/null +++ b/assets/xml/soundfonts/Ganon's Castle.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/assets/xml/soundfonts/Ganondorf's Battle.xml b/assets/xml/soundfonts/Ganondorf's Battle.xml new file mode 100644 index 00000000000..af0ab3e80cf --- /dev/null +++ b/assets/xml/soundfonts/Ganondorf's Battle.xml @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/xml/soundfonts/Gerudo Valley.xml b/assets/xml/soundfonts/Gerudo Valley.xml new file mode 100644 index 00000000000..116d4615a6a --- /dev/null +++ b/assets/xml/soundfonts/Gerudo Valley.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/assets/xml/soundfonts/Goron City.xml b/assets/xml/soundfonts/Goron City.xml new file mode 100644 index 00000000000..a61aba5f0b3 --- /dev/null +++ b/assets/xml/soundfonts/Goron City.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/assets/xml/soundfonts/Horse Race.xml b/assets/xml/soundfonts/Horse Race.xml new file mode 100644 index 00000000000..8f88e0300f2 --- /dev/null +++ b/assets/xml/soundfonts/Horse Race.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/xml/soundfonts/Ice Cavern.xml b/assets/xml/soundfonts/Ice Cavern.xml new file mode 100644 index 00000000000..7086c29aa10 --- /dev/null +++ b/assets/xml/soundfonts/Ice Cavern.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/assets/xml/soundfonts/Jabu Jabu.xml b/assets/xml/soundfonts/Jabu Jabu.xml new file mode 100644 index 00000000000..cb7cc01d499 --- /dev/null +++ b/assets/xml/soundfonts/Jabu Jabu.xml @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/xml/soundfonts/Kaepora Gaebora's Theme.xml b/assets/xml/soundfonts/Kaepora Gaebora's Theme.xml new file mode 100644 index 00000000000..6aac7c12db4 --- /dev/null +++ b/assets/xml/soundfonts/Kaepora Gaebora's Theme.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/xml/soundfonts/Kakariko Village (Child).xml b/assets/xml/soundfonts/Kakariko Village (Child).xml new file mode 100644 index 00000000000..59287ff47b1 --- /dev/null +++ b/assets/xml/soundfonts/Kakariko Village (Child).xml @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/xml/soundfonts/Kokiri Forest.xml b/assets/xml/soundfonts/Kokiri Forest.xml new file mode 100644 index 00000000000..9771aa82714 --- /dev/null +++ b/assets/xml/soundfonts/Kokiri Forest.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/xml/soundfonts/Kotake and Koume's Theme.xml b/assets/xml/soundfonts/Kotake and Koume's Theme.xml new file mode 100644 index 00000000000..ab55d52f35f --- /dev/null +++ b/assets/xml/soundfonts/Kotake and Koume's Theme.xml @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/xml/soundfonts/Laboratory.xml b/assets/xml/soundfonts/Laboratory.xml new file mode 100644 index 00000000000..cbc9e92452b --- /dev/null +++ b/assets/xml/soundfonts/Laboratory.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/assets/xml/soundfonts/Legends of Hyrule.xml b/assets/xml/soundfonts/Legends of Hyrule.xml new file mode 100644 index 00000000000..dab070599fd --- /dev/null +++ b/assets/xml/soundfonts/Legends of Hyrule.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/assets/xml/soundfonts/Lon Lon Ranch.xml b/assets/xml/soundfonts/Lon Lon Ranch.xml new file mode 100644 index 00000000000..fe7c2402b45 --- /dev/null +++ b/assets/xml/soundfonts/Lon Lon Ranch.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/xml/soundfonts/Market.xml b/assets/xml/soundfonts/Market.xml new file mode 100644 index 00000000000..646f1f27a2d --- /dev/null +++ b/assets/xml/soundfonts/Market.xml @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/xml/soundfonts/Minigames.xml b/assets/xml/soundfonts/Minigames.xml new file mode 100644 index 00000000000..5da6a3e973f --- /dev/null +++ b/assets/xml/soundfonts/Minigames.xml @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/xml/soundfonts/Orchestra.xml b/assets/xml/soundfonts/Orchestra.xml new file mode 100644 index 00000000000..e42d99921f7 --- /dev/null +++ b/assets/xml/soundfonts/Orchestra.xml @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/xml/soundfonts/Shadow Temple.xml b/assets/xml/soundfonts/Shadow Temple.xml new file mode 100644 index 00000000000..83d661fde19 --- /dev/null +++ b/assets/xml/soundfonts/Shadow Temple.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/assets/xml/soundfonts/Shops.xml b/assets/xml/soundfonts/Shops.xml new file mode 100644 index 00000000000..466503a5a06 --- /dev/null +++ b/assets/xml/soundfonts/Shops.xml @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/xml/soundfonts/Sound Effects 1.xml b/assets/xml/soundfonts/Sound Effects 1.xml new file mode 100644 index 00000000000..d84e45064cc --- /dev/null +++ b/assets/xml/soundfonts/Sound Effects 1.xml @@ -0,0 +1,242 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/xml/soundfonts/Sound Effects 2.xml b/assets/xml/soundfonts/Sound Effects 2.xml new file mode 100644 index 00000000000..4aa2e6199fa --- /dev/null +++ b/assets/xml/soundfonts/Sound Effects 2.xml @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/xml/soundfonts/Spirit Temple.xml b/assets/xml/soundfonts/Spirit Temple.xml new file mode 100644 index 00000000000..f9fbc4ef3a4 --- /dev/null +++ b/assets/xml/soundfonts/Spirit Temple.xml @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/xml/soundfonts/Title Theme.xml b/assets/xml/soundfonts/Title Theme.xml new file mode 100644 index 00000000000..cfce230830e --- /dev/null +++ b/assets/xml/soundfonts/Title Theme.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/xml/soundfonts/Unused.xml b/assets/xml/soundfonts/Unused.xml new file mode 100644 index 00000000000..d58e1aa05b2 --- /dev/null +++ b/assets/xml/soundfonts/Unused.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/xml/soundfonts/Warp Songs.xml b/assets/xml/soundfonts/Warp Songs.xml new file mode 100644 index 00000000000..e2dda90b624 --- /dev/null +++ b/assets/xml/soundfonts/Warp Songs.xml @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/xml/soundfonts/Water Temple.xml b/assets/xml/soundfonts/Water Temple.xml new file mode 100644 index 00000000000..61879ed2364 --- /dev/null +++ b/assets/xml/soundfonts/Water Temple.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/assets/xml/soundfonts/Zora's Domain.xml b/assets/xml/soundfonts/Zora's Domain.xml new file mode 100644 index 00000000000..09f736e9c72 --- /dev/null +++ b/assets/xml/soundfonts/Zora's Domain.xml @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/data/audio_pad.rodata.s b/data/audio_pad.rodata.s new file mode 100644 index 00000000000..2ea0c2f4ca5 --- /dev/null +++ b/data/audio_pad.rodata.s @@ -0,0 +1,11 @@ +.include "macro.inc" + +# assembler directives +.set noat # allow manual use of $at +.set noreorder # don't insert nops after branches +.set gp=64 # allow use of 64-bit general purpose registers + +.section .rodata + +.balign 16 +.fill 0x20 diff --git a/data/audio_tables.rodata.s b/data/audio_tables.rodata.s deleted file mode 100644 index fb31af24b22..00000000000 --- a/data/audio_tables.rodata.s +++ /dev/null @@ -1,22 +0,0 @@ -.include "macro.inc" - -# assembler directives -.set noat # allow manual use of $at -.set noreorder # don't insert nops after branches -.set gp=64 # allow use of 64-bit general purpose registers - -.section .rodata - -.balign 16 - -glabel gSoundFontTable - .incbin "baserom.z64", 0xBCC270, 0x270 - -glabel gSequenceFontTable - .incbin "baserom.z64", 0xBCC4E0, 0x1C0 - -glabel gSequenceTable - .incbin "baserom.z64", 0xBCC6A0, 0x6F0 - -glabel gSampleBankTable - .incbin "baserom.z64", 0xBCCD90, 0x80 diff --git a/docs/Music Macro Language.md b/docs/Music Macro Language.md new file mode 100644 index 00000000000..44946b2ceab --- /dev/null +++ b/docs/Music Macro Language.md @@ -0,0 +1,989 @@ +# Music Macro Language + +Ocarina of Time contains a number of files known as **sequences**. These sequences typically represent the music that plays during regular gameplay, such as Hyrule Field's theme or the Fire Temple background music. These sequences are comparable to General MIDI version 1 with some noticeable differences, but the language that composes these sequences is much more complex and can support more programmatic uses. Ocarina of Time in particular uses this language in innovative ways, which are described later in this document. + +Note that if you have not read the documentation describing how the audio subsystem works in Ocarina of Time, it's *strongly* recommended that you read that document first, as it provides a high-level description of how the audio library works and its different components. It will be assumed that you are familiar with the terms and concepts introduced in that document here. + +The macro language is very similar conceptually to an assembly language or tracker file, with the ability to loop, change parameters and configuration settings, switch between soundfonts, interact with the game engine to allow for dynamic changes, and randomization. + +## Structure of a Sequence + +Generally, a sequence is composed in three major sections: descriptor, track, and data. Each of these sections is different from the other, and in some cases they may be interleaved with each other. For example, if a sequence has multiple subsequences embedded inside it, those subsequences may contain their own data sections. + +### Primitives and Labels + +Sequences may contain primitives, such as text and integers, which can be used as parameters for instructions or entries. + +**Strings**: A series of Unicode characters enclosed by quotation marks. For example: `"this is a string"`. + +**Integers**: Numerical values without a fractional component. For most usages, the integer must be within a certain supported range (as documented). An integer can be written in decimal, hexadecimal, or binary, whichever feels most appropriate. For example: `123`, `0x7B`, or `0b01111011`. + +**Labels** allow you to provide a label for a certain subsection of the track code or data values. They are defined using a related metacommand (documented in the next section), which specifies the label type. Labels may consist of a series of Unicode letters or numbers, as well as underscores and periods. You may then reference that label in your track code or data where the label type is accepted (as documented). You can also use relative offsets around a label if you want to adjust where you're pointing to relative to the location of the label. + +All label names must be unique. If you define the same label in multiple locations of the sequence, this will result in an error. Note that this applies across label types; for example, a channel label called `percussion` prevents a note layer label from being called `percussion`. + +For example, this illustrates the usage of labels to reference a channel label: +``` +ldchan 1, chan1_script +end + +.channel chan1_script +... various channel instructions ... +``` + +The following illustrates the usage of label offsets to allow rewriting a parameter to a command: +``` +stseq 5, notecmd+1 # Changes the pitch played by the notedvg command +... +.layer notecmd +notedvg 0, 10, 127 # The first parameter here will be changed to 5 +``` + +### Comments and Metainstructions + +Comments allow you to provide information that may be valuable to those who read the sequence contents directly. These can provide documentation or explain more complex logic used in the sequence and are particularly useful for more complex, programmatic sequences. + +A comment always starts with a # character. This may appear anywhere in a line, and all text after the # will be ignored by editors or parsers. These comments will not be saved or stored in the binary representation of a sequence. They are purely for documentation purposes only. + +Metainstructions are instructions that are read by the editor or parser, but do not get stored in the resultant binary file directly. The following metainstructions are supported by the parser provided by `assemble_sequence`. Other tools may support additional metainstructions, but these are always supported by all tools. + +**.define** *symbol* *value* + +**Description:** Defines a symbol that may be used elsewhere in the sequence script. The symbol may consist of any Unicode letter, number, or underscores. The value must be a primitive value. Symbols must be defined only once in a sequence, similar to + +**Parameters:** + +* `symbol` - The symbol being defined in the sequence. +* `value` - A primitive that will the symbol represents. + +**Example:** +``` +.define IO_PORT_FXID 0 # Defines a symbol called IO_PORT_FXID with a value of 0. + +ldio IO_PORT_IO # Loads a value from IO port 0. +``` + +**.include** *filename* + +**Description:** Defines a sequence file to be included into this sequence. When processing, this will embed the contents of that file precisely where it's included with the `.include` directive. The filename provided must be a path relative to this sequence file and enclosed with double quotes. Note that care must be taken not to include the same file multiple times, or to have two or more files include each other in a way that would result in an infinite loop. + +Symbols and labels exist in a global scope across all included files. This means that any symbol or label defined in one file may be used in any other file, even if the file referencing that label does not include the file defining the label directly. So long as the label is included somewhere, it can be referenced. + +**Parameters:** +* `filename` - The relative path to the sequence file to include at this point in the sequence. + +**Example:** + +The following example consists of three different files: `example.mus`, the main sequence; `constants.inc`, a file containing constants used across the sequence files; and `alternate.mus.inc`, containing an alternate section that plays when the game prompts it to do so. + +**example.mus** +``` +.desc title Example Sequence +.desc author zeldaret +.usefont SOUNDFONT_ORCHESTRA +.include "constants.inc" # This is the same as though constants.inc was written directly here. + +.sequence start +mutebhv 0x20 +mutescale 50 +initchan 0b0000000000000001 # Only channel 0 is used. +ldchan 0, channel0_main # Play the main tune first. +vol 70 +tempo 64 +delay 150 +.sequence main_loop_start +ldio IO_PORT_MAIN # Reads from the IO port. If false, uses the alternate melody, otherwise it uses the main melody. +beqz use_alternate_melody +ldchan 0, channel0_main +delay 150 +jump main_loop_start +.sequence use_alternate_melody +ldi TRUE # Prevents the alternate melody from being played again until the game signals it. +stio IO_PORT_ALT +ldchan 0, channel0_alt +delay 150 +jump main_loop_start +end + +.channel channel0_main +... various instructions here ... +end + +.include "alternate.mus.inc" # This is the same as though alternate.mus.inc was written directly here. +``` + +**constants.inc** +``` +# IO port 0: Signals to the sequence to play an alternate melody instead of the main melody. +.define IO_PORT_MAIN 0 + +# Binary values +.define TRUE 1 +.define FALSE 0 +``` + +**alternate.mus.inc** +``` +.desc title Alternate Melody + +.channel channel0_alt +... various instructions here... +end +``` + +**Label Metainstructions** + +The following metainstructions allow you to define a label that points to the relevant set of instructions. These metainstructions are the following: + +| Metacommand | Description | +| ----------- | ----------------------------------------------------------- | +| .sequence | A series of sequence instructions within a track section. | +| .channel | A series of channel instructions within a track section. | +| .layer | A series of note layer instructions within a track section. | +| .table | A table of entries or bytes within a data section. | +| .array | An array of bytes or shorts in a data section. | +| .filter | References a filter structure in a data section. | +| .envelope | References an envelope structure in a data section. | +| .buffer | References a buffer within a data section. | + +**Section Metainstructions** + +There are metainstructions specific to certain sections that will be documented in those sections specifically. These will be described in those sections as appropriate. Note that metainstructions are always distinguished by starting with a period, whereas instructions do not. + +### Descriptor Section + +The descriptor section is composed of instructions that provide information useful for describing the sequence. The only required command for this section is .usefont, which may only be used at the very beginning of the track and defines what soundfonts will be available for use by the sequence. + +#### Metainstructions + +*Descriptor instructions have no binary representation.* + +**.desc** *type* *text* + +**Description:** A descriptor to provide information to users and editors. Type can be any single word, but the most commonly used are *title* and *author*. + +**Example:** +``` +.desc title "An Example Sequence" +.desc author "zeldaret" +``` + +**.usefont** *index* + +**Description:** Specifies a soundfont that should be available for the sequence to use. The first soundfont specified will be active by default when loaded by the game. Note that the game never uses more than two soundfonts for a sequence, but more than two are theoretically supported. + +**Example:** +``` +.usefont 1 # Can also use SOUNDFONT_SFX_1 +.usefont 3 # See sequence.inc for other soundfont constants +``` + +### Track Section + +Tracks are composed of three different types of instructions: sequence, channel, and note layer. The sequence contains instructions for controlling the overall sequence itself. Channels are defined at the sequence level, with at most sixteen channels running at the same time. Each channel can then reference zero or more note layers, where the actual note instructions will be referenced. Most of the instructions are specific to these subsections and are not interchangeable, aside from the *Branching instructions*, which are supported with all three. A sequence *always* starts with sequence instructions. + +Tracks are executed by the **sequence player**, as defined in `audio_seqplayer.c`. The sequence player is capable of executing one track at a time, with sixteen simultaneous channels, each channel typically supporting four note layers. A tick counter allows the player to track the execution time of a sequence. Ticks increment based by the tempo. + +All instructions in a track section are executed simultaneously unless a delay command is specified, in which case subsequent instructions will only run after that number of ticks have elapsed while playing the sequence. + +A track can loop (potentially) indefinitely by using branching instructions, or can end if the sequence command `end` is encountered. This will end processing of the sequence, and the sequence player will no longer process any further instructions until a new sequence is started. + +#### Long Notes Versus Short Notes + +The sequence format supports two different ways of representing note instructions in binary: long and short. + +Short notes only encode the pitch being played and optionally the note duration (delay). This can provide significant space savings when the notes being played are all using the same gate and velocity (a drum section, for example, with a continuous drum roll). There are dedicated instructions that allow you to change the gate and velocity parameters, either setting default values or changing the parameters for following notes. + +Long notes, in comparison, encode the pitch and velocity with each command, in addition to either the duration, gate length, or both. This provides better space savings compared to short notes if the gate or velocity parameters change frequently with each note, as it can take two or more bytes to do this with short notes rather than one additional byte with the long note. Long note mode is recommended most with melodic sections, where your instruments are intended to be more expressive. + +#### Sequence Subsections + +##### Sequence Registers + +Certain instructions support loading or storing values and utilize a register associated to the sequence for this task. For documentation purposes, this is referred to as the `$V` register. This register is one byte in size; most instructions treat it as a signed value. + +##### IO Ports + +Each sequence player contains 8 IO ports that are one byte in size each. These ports can be used to communicate state information between other parts of the game engine, or across different parts of the sequence. For example, a sequence script could use an IO port that, when set to a certain value, changes what instrument is used. + +##### Metainstructions + +**.sequence** *label name* + +**Description:** Defines a label for the following subsection of sequence instructions. Note that it is considered an error if a sequence label is proceeded with anything that is not a sequence command. + +**Example:** +``` +.sequence loop_start +ldchan 1, chan1_melody +delay 500 +jump loop_start # Plays the same melody indefinitely. +``` + +##### Instructions + +| | 00 | 10 | 20 | 30 | 40 | 50 | 60 | 70 | 80 | 90 | A0 | B0 | C0 | D0 | E0 | F0 | +| -- | -------- | -- | -- | -- | -------- | ----- | ----- | ---- | ---- | ------ | ------- | ----- | --------- | ----------- | -- | ------------- | +| 00 | testchan | | | | stopchan | subio | ldres | stio | ldio | ldchan | rldchan | ldseq | | notealloc | | freenotelist | +| 01 | testchan | | | | stopchan | subio | ldres | stio | ldio | ldchan | rldchan | ldseq | | ldshortgate | | allocnotelist | +| 02 | testchan | | | | stopchan | subio | ldres | stio | ldio | ldchan | rldchan | ldseq | | ldshortvel | | *rbltz | +| 03 | testchan | | | | stopchan | subio | ldres | stio | ldio | ldchan | rldchan | ldseq | | mutebhv | | *rbeqz | +| 04 | testchan | | | | stopchan | subio | ldres | stio | ldio | ldchan | rldchan | ldseq | runseq | mute | | *rjump | +| 05 | testchan | | | | stopchan | subio | ldres | stio | ldio | ldchan | rldchan | ldseq | scriptctr | mutescale | | *bgez | +| 06 | testchan | | | | stopchan | subio | ldres | stio | ldio | ldchan | rldchan | ldseq | stop | | | *break | +| 07 | testchan | | | | stopchan | subio | ldres | stio | ldio | ldchan | rldchan | ldseq | stseq | initchan | | *loopend | +| 08 | testchan | | | | stopchan | subio | ldres | stio | ldio | ldchan | rldchan | ldseq | sub | | | *loop | +| 09 | testchan | | | | stopchan | subio | ldres | stio | ldio | ldchan | rldchan | ldseq | and | fadescale | | *bltz | +| 0A | testchan | | | | stopchan | subio | ldres | stio | ldio | ldchan | rldchan | ldseq | | fade | | *beqz | +| 0B | testchan | | | | stopchan | subio | ldres | stio | ldio | ldchan | rldchan | ldseq | | fadetovol | | *jump | +| 0C | testchan | | | | stopchan | subio | ldres | stio | ldio | ldchan | rldchan | ldseq | ldi | tempochg | | *call | +| 0D | testchan | | | | stopchan | subio | ldres | stio | ldio | ldchan | rldchan | ldseq | dyncall | tempo | | *delay | +| 0E | testchan | | | | stopchan | subio | ldres | stio | ldio | ldchan | rldchan | ldseq | rand | rtranspose | | *delay1 | +| 0F | testchan | | | | stopchan | subio | ldres | stio | ldio | ldchan | rldchan | ldseq | | transpose | | *end | + +Instructions marked with an asterisk (\*) are documented in the section *Branching Instructions*. + +**testchan** *N* + +**Description:** Stores whether or not channel *N* is currently active in `$V`. If the channel is active, `$V` will equal `0`, otherwise it will equal `1`. + +**Parameters:** +* `N` [integer: 0-15] - The channel number to test. + +**Example:** +``` +.sequence wait_until_done +delay1 +testchan 1 +beqz wait_until_done +# Instructions here only execute once channel 1 reaches an end command. +``` + +**stopchan** *N* + +**Description:** Stops channel *N* from executing any further instructions. Any notes currently playing on the channel will cease. + +**Parameters:** +* `N` [integer: 0-15] - The channel number to stop. + +**Example:** +``` +ldchan 0, chan0 +ldchan 1, chan1 +delay 50 +stopchan 1 # Stops channel 1 after 50 ticks, even if there's additional instructions. +``` + +**subio** *N* + +**Description:** Subtracts from `$V` whatever value is in IO port *N*. + +**Parameters:** +* `N` [integer: 0-7] - The IO port to read. + +**Example:** +``` +# Assume that the current value in $V is 5 and the current value in IO port 1 is -5. +subio 1 +stio 0 +# IO port 0 now contains the current value of $V, which is 0. +``` + +**ldres** *IO*, *type*, *index* + +**Description:** Loads an audio resource into memory asynchronously. The type of resource is specified via *type*, where 0 is a sequence, 1 is a soundfont, and 2 is a sample bank. The IO parameter is used to track the status of the loading process. The audio subsystem will update this value to 0 once the resource has been loaded. Note that the IO port doesn't change this value to anything but 0 first, so it's recommended to set the IO port to a non-zero value prior to using `ldres`. + +Unlike the dedicated `ldseq` command, this does not assign the loaded sequence to a sequence player for playback. This was likely intended to be paired with `runseq`, since the sequence would be loaded into the pool and ready for playback immediately and wouldn't introduce any processing lag. Unfortunately, with the way the pools are designed, this is suboptimal and could introduce issues. + +As a best practice, if you want to do dynamic sequence changes, allocate a buffer inside your sequence and use `ldseq` to load it into the buffer and call it as a sequence function. If you want to change the sequence being played by another sequence player, you must use the `ldres` and `runseq` instructions. + +You do not need to use this command to load sample banks or soundfonts. There are no instructions to allow a sequence to use an arbitrary soundfont, and any soundfonts assigned to a sequence are preemptively loaded into the pool prior to the sequence player initializing. The engine also already handles loading sample banks and samples automatically, so there are no useful situations where you would need to use this command with sample banks. + +**Parameters:** +* `IO` [integer: 0-7] - The IO port to use for tracking the asynchronous load status. +* `type` [integer: 0-2] - The type of resource to load. +* `index` [integer: 0-255] - The index of the resource to load from the table. + +**Example:** +``` +ldi -1 +stio 5 +ldres 5, 0, 10 # Loads sequence 10 and signals the load in IO port 5. +.sequence wait_for_sequence +delay1 +ldio 5 +bltz wait_for_sequence +``` + +**stio** *IO* + +**Description:** Stores the current value in `$V` into the IO port specified. + +**Parameters:** +* `IO` [integer: 0-7] - The IO port to store the contents of `$V` into. + +**Example:** +``` +ldi 10 +stio 0 # Stores the value 10 into IO port 0. +``` + +**ldio** *IO* + +**Description:** Reads the value in the specified IO port and stores it in `$V`. + +**Parameters:** +* `IO` [integer: 0-7] - The IO port to read from. + +**Example:** +``` +ldio 1 # Reads the value in IO port 1 and stores in $V. +stseq 0, volchange+1 # Writes the value in $V to the next instruction's first parameter. +.sequence volchange +fadetovol 0 # Changes the sequence player's volume to the value in $V. +``` + +**ldchan** *N* *label* + +**Description:** Assigns a channel script to the specified channel, which will begin executing on the current tick. If the channel already was executing a script, the channel will immediately begin executing this script's instructions instead. The label must be a channel label. + +**Parameters:** +* `N` [integer: 0-15] - The channel to assign the script to. +* `label` [channel label] - The label of channel instructions to assign to the channel. + +**Example:** +``` +ldchan 0, chan0 +... + +.channel chan0 +resetchan +end +``` + +**rldchan** *N* *label* + +**Description:** Assigns a channel script to the specified channel, similar in functionality to `ldchan`. The only difference between this command and `ldchan` is that this uses a relative offset versus an absolute offset when converted to binary form. Use this when the sequence's position in memory is not guaranteed to be in a certain position (for example, when using `ldseq`). + +**Parameters:** +* `N` [integer: 0-15] - The channel to assign the script to. +* `label` [channel label] - The label of channel instructions to assign to the channel. + +**Example:** +``` +rldchan 0, chan0 +... + +.channel chan0 +resetchan +end +``` + +**ldseq** *IO* *index* *label* + +**Description:** Loads the specified sequence asynchronously into the buffer space specified by the given label. The IO port will be used to signal when the sequence has been fully loaded into the buffer. The enum `SlowLoadStatus` is used by the audio subsystem to indicate the current loading status. The IO port will be set to 3 on the tick that the sequence is loaded, and then 0 after. + +Note that the sequence player and audio subsystem are unable to detect if a buffer overflow will occur when loading the sequence. Be certain that the buffer you use is large enough to contain the loaded sequence, otherwise the load could corrupt the main sequence or other parts of the sequence player's state. + +**Parameters:** +* `IO` [integer: 0-7] - The IO port to use for tracking the load of the sequence. +* `index` [integer: 0-127] - The sequence ID to be loaded into the buffer. +* `label` [buffer label] - The buffer to load the sequence into. + +**Example:** +``` +rand 2 # Randomly loads either sequence 5 or 10. +beqz .load_seq_5 +ldseq 0, 10, seqbuf # Loads sequence 10 into the buffer. +jump wait_for_load +.sequence load_seq_5 +ldseq 0, 5, seqbuf # Loads sequence 5 into the buffer. +.sequence wait_for_load +delay1 +ldio 0 +bltz wait_for_load # If IO port 0 is not 0, continue waiting for sequence to load. +dyncall bufptr # Call the sequence in seqbuf as a subroutine. +end + +.data + +.table bufptr +.entry seqbuf + +.buffer seqbuf # A buffer that the sequence will be loaded into. +.space 0x2048 # The buffer is 2KB in size. +``` + +**runseq** *player*, *index* + +**Description:** Instructs the specified sequence player to play the specified sequence. Unlike most instructions, this one operates synchronously and will block execution of the current sequence script until the command finishes (presumably, this is to avoid potential race conditions if you replace the sequence in the current sequence player). If you want to specifically change the sequence being played by the current player, you can use `0xFF` for the player. + +If this command modifies the current sequence player, the sequence player will reset and no longer execute the original script. Otherwise, the sequence player will continue to play once the other sequence player has finished loading. + +**Parameters:** +* `player` [integer: 0-3, 255] - The sequence player to modify. If 255, use current. +* `index` [integer: 0-127] - The sequence index to load into the sequence player. + +**Example:** +``` +# Assumes that this script is running in sequence player 0. +runseq 1, 5 # Instructs sequence player 1 to load and play sequence 5. This sequence will not + # continue until sequence player 1 finishes loading. +``` + +**scriptctr** *counter* + +**Description:** Changes the current script counter. Note that this counter increments, but never is used by the audio subsystem otherwise. This should not be confused for the tick or tempo. + +**Parameters:** +* `counter` [integer: 0-65535] - What to set the counter value to. + +**Example:** +``` +scriptctr 0 # Sets the script counter to 0. This has no impact on the sequence itself. +``` + +**halt** + +**Description:** Halts any further processing of the current sequence after this tick. + +**Parameters:** None. + +**Example:** +``` +ldchan 1, chan1 +halt # Channel 1 will run for one tick before the script ends. +``` + +**stseq** *val*, *offset/label* + +**Description:** Writes the total of `$V` + `val` to the offset within the sequence script in its binary form. The easiest way to use this command is to use a label within the script pointing to the command/data you wish to modify. + +Note that this instruction modifies the sequence script itself and is a form of self-modifying code. This can be leveraged to make highly dynamic sequences (and is used to great effect in the sound effects sequence), but using it improperly can easily cause sequence corruption and undefined behavior. + +**Parameters:** +* `val` [integer: 0-255] - Constant to add to `$V`. +* `offset/label` [integer: 0-32767 or any label] - Offset or label to location in sequence to be modified. + +**Example:** +``` +ldchan 5, chan5 +ldi 7 +stseq 0, chan5_instr+1 # Changes the instrument specified in chan5 to 7. +delay 500 +end + +.channel chan5 +short +.channel chan5_instr +instr 3 +... +``` + +**sub** *val* + +**Description:** Subtracts the specified integer from the current value stored in the `$V` register. + +**Parameters:** +* `val` [integer: 0-255] - Value to subtract + +**Example:** +``` +ldio 3 # Load value from IO port 3 into $V +sub 2 # $V -= 2 +stio 3 # Store $V to IO port 3 +``` + +**and** *val* + +**Description:** Performs a bitwise and operation between the value stored in the `$V` register and the value specified. + +**Parameters:** +* `val` [integer: 0-255] - Value to perform a bitwise and with + +**Example:** +``` +ldio 3 # Load value from IO port 3 into $V +and 0xF0 # Set lower four bits to 0 +stio 2 # Store resulting value into IO port 2 +``` + +**ldi** *val* + +**Description:** Sets the `$V` register to the provided integer. + +**Parameters:** +* `val` [integer: 0-255] - Value to load into the register + +**Example:** +``` +ldi 2 # $V = 2 +stio 0 # Set IO port 0 to 2 +``` + +**dyncall** *table* + +**Description:** Makes a function call using an entry from the specified table in a data section. The value in the `$V` register is treated as the index to look up within the table. Once an `end` command is reached in the called function, the player will return back and execute the next instruction after this one. + +If `$V` is currently set to -1 or the call depth is at 3, then the function call will fail and be skipped. Note that the sequence player does not perform any bounds checking on `$V`; if it's larger than the table, the sequence player will jump to a potentially unexpected location in the script and could result in undefined behavior. + +**Parameters:** +* `table` [table label] - A label to an entry table + +**Example:** +``` +rand 3 +dyncall play_funcs +.sequence wait_for_finish +delay1 +ldio 7 +bltz wait_for_finish +end + +.sequence option1 +... instructions for one sequence ... +end + +.sequence option2 +... instructions for a completely different sequence ... +end + +.sequence option3 +... instructions for a remixed sequence between the two ... +end + +.data + +.table play_funcs +.entry option1 +.entry option2 +.entry option3 +``` + +**rand** *max* + +**Description:** Assigns a random integer to the `$V` register between `0` (inclusive) and `max` (exclusive). If `max` is 0, then it will be any random value between `-128` (inclusive) and `127`. + +Note that a side effect of the implementation for this command is that if a maximum of 1 is used, then this will always set `$V` to 0. In addition, the `$V` register is signed even though the random value is calculated entirely with unsigned values. As a result, although you can set the maximum to a value larger than 127, it is not recommended as this will not interact well with most other instructions. + +**Parameters:** +* `max` [integer: 0-255] - The maximum (exclusive) to use for the random value, or 0 for any random value to be chosen + +**Example:** +``` +rand 50 # $V = value between 0 and 49 +stseq 50, volume+1 # vol param set to $V + 50 +volmode 1 # Set volume mode to fade +.sequence volume +vol 0 # Change volume to $V + 50 +``` + +**notealloc** *mask* + +**Description:** Sets the note allocation policy based on the provided flags. This policy is applied to any channels initialized after this command executes. The bitmask uses the following flags: + +* 0b0001 - The note layer will reuse the same note when another note is played. +* 0b0010 - Only allocates notes from the channel's current reserved note pool. +* 0b0100 - Only allocates notes from the channel or sequence's reserved note pool. +* 0b1000 - Only allocates notes from the global note pool. + +If none of the upper three bits are set, then the note will be allocated from any available source (channel, sequence player, or global). The audio subsystem will first try the channel reserved pool, then the sequence player reserved pool, and finally the global note pool. + +This policy is assigned to the channels when the `initchan` command is executed; using this command after the channels are initialized will have no effect unless `initchan` is called again. + +**Parameters:** +* `mask` [integer: 0-15] - The note allocation policy to use. + +**Example:** +``` +notealloc 0b0010 # Channels 0 and 1 will always play notes from the channel's pool +ldchan 0, violin # without replacing any playing notes +ldchan 1, strings +notealloc 0b0101 # Channels 3 and 9 will play notes from the channel or sequence's pools +ldchan 3, piano # and replace playing notes if needed +ldchan 9, percussion +notealloc 0b1000 # Channel 4 will play notes from any free note list without any stealing +ldchan 4, triangle +``` + +**ldshortgatearr** *array* + +**Description:** Loads the specified byte array of note gate values into the sequence player. This array can be used in the note layer by the `ldshortgate` command. This allows you to change gate values for consecutive notes with only a single byte, however only up to 16 values can be read from the array. + +Note that the short note gate array applies across all channels and note layers in the sequence player. If the array is changed at any point, this will also change the gate array for all note layers simultaneously. This will not affect the gate values already loaded. + +If this command is not used but the `ldshortgate` is used, the gate value will be read from `gDefaultShortNoteGateTimeTable`, which consists of the following values: + +`{ 229, 203, 177, 151, 139, 126, 113, 100, 87, 74, 61, 48, 36, 23, 10, 0 }` + +**Parameters:** +* `array` [array label] - Label to an array in a data section containing up to sixteen bytes. + +**Example:** +``` +ldshortgatearr shortgates # Assigns the array shortgates to the player's short note lookup table +ldchan 0, chan0 # Loads channel 0 +delay 500 +end + +.channel chan0 +short # Activates short note mode on this channel +ldlayer layer0 # Loads note layer 0 for this channel +delay 500 +end + +.layer layer0 +ldshortgate 5 # Loads gate value at index 5 (150) to be used for subsequent notes. +notedvg PITCH_C4, 6, 0 # Plays C4 with gate 27 and duration of 6 ticks. +notevg PITCH_D4, 6, 0 # Plays D4 with gate 27 and the same duration as previous. +notevg PITCH_F4, 6, 0 +ldshortgate 3 # Loads gate value at index 3 (100) to be used for subsequent notes. +notevg PITCH_G4, 6, 0 # Plays G4 with gate 10 and same duration as previous. +notevg PITCH_G4, 6, 0 +notevg PITCH_C5, 6, 0 + +.data + +.array shortgates +.byte 20 +.byte 50 +.byte 80 +.byte 100 +.byte 120 +.byte 150 +.byte 180 +``` + +**ldshortvelarr** *array* + +**Description:** Loads the specified byte array of note velocity values into the sequence player. This array can be used in the note layer by the `ldshortvel` command. This allows you to change velocity values for consecutive notes with only a single byte, however only up to 16 values can be read from the array. + +Note that the short note velocity array applies across all channels and note layers in the sequence player. If the array is changed at any point, this will also change the velocity array for all note layers simultaneously. This will not affect the velocity values already loaded. + +If this command is not used but the `ldshortvel` is used, the velocity value will be read from `gDefaultShortNoteVelocityTable`, which consists of the following values: + +`{ 12, 25, 38, 51, 57, 64, 71, 76, 83, 89, 96, 102, 109, 115, 121, 127 }` + +**Parameters:** +* `array` [array label] - Label to an array in a data section containing up to sixteen bytes. + +**Example:** +``` +ldshortvelarr shortvels # Assigns the array shortgates to the player's short note lookup table +ldchan 0, chan0 # Loads channel 0 +delay 500 +end + +.channel chan0 +short # Activates short note mode on this channel +ldlayer layer0 # Loads note layer 0 for this channel +delay 500 +end + +.layer layer0 +ldshortvel 5 # Loads gate value at index 5 (27) to be used for subsequent notes. +notedvg PITCH_C4, 6, 0 # Plays C4 with gate 27 and duration of 6 ticks. +notevg PITCH_D4, 6, 0 # Plays D4 with gate 27 and the same duration as previous. +notevg PITCH_F4, 6, 0 +ldshortgate 3 # Loads gate value at index 3 (10) to be used for subsequent notes. +notevg PITCH_G4, 6, 0 # Plays G4 with gate 10 and same duration as previous. +notevg PITCH_G4, 6, 0 +notevg PITCH_C5, 6, 0 + +.data + +.array shortvel +.byte 4 +.byte 5 +.byte 8 +.byte 10 +.byte 20 +.byte 27 +.byte 50 +``` + +**mutebhv** *mask* + +**Description:** Defines the sequence player's behavior when the mute mode is enabled. The following flags can be ORed together and provided in the `mask` parameter. This behavior is assigned to the channels when the `initchan` command is executed; using this command after the channels are initialized will have no effect unless `initchan` is called again. + +* 0b00000001 - Unused. +* 0b00000010 - Unused. +* 0b00000100 - Unused. +* 0b00001000 - Immediately stops playing notes when muted. +* 0b00010000 - All note layers will stop playing any new notes when muted. Old notes will play for their remaining duration. +* 0b00100000 - Reduces the sequence player's volume by the mute volume scale when muted. +* 0b01000000 - All note layers will stop playing any new notes and cut off old notes when muted. +* 0b10000000 - Stops processing completely when muted. + +The default mute behavior for the sequence player is 0b01100000. + +Note that the mute behavior mostly is only affected by the `mute` command. The game also supports dynamic muting via the channel command `STOPSOMETHING2`, which will stop playing new notes for that channel (this operates separately from the mute behavior). It also supports toggling mute mode for all sequence players via audio instructions `0xF1` and `0xF2`. + +**Parameters:** +* `mask` [integer: 0-65535] - The default mute behavior for the sequence. + +**Example:** +``` +mutebhv 0x20 # Sets mute behavior to reduce volume. +mutescale 63 # Scales volume to 49.6%. +ldchan 1, chan1 # Plays channel 1 at full volume. +delay 500 +mute # Plays channel 1 at half volume. +delay 500 +end +``` + +**mute** + +**Description:** Activates mute mode for the sequence player. How this is treated depends on the behavior set by `mutebhv`. By default, the player will reduce volume and also immediately stop playing all notes. + +Once mute has been activated, it cannot be disabled again via command. + +**Parameters:** None. + +**Example:** +``` +ldchan 1, chan1 # Starts playing channel 1. +delay 500 +mute # Mutes the sequence. +delay 40 +end +``` + +**mutescale** *numerator* + +**Description:** Sets the fractional value that should be applied to the sequence's current volume when mute mode is enabled. The value passed in the parameter will be divided by 127 and the result stored in the sequence player's configuration. Unlike `mutebhv`, this can be used at any point in the sequence to change the mute scale factor. + +For example, if set to 127 and the sequence is muted, the volume will not reduce at all. If set to 80, the volume will reduce by 63%. If set to 0, the volume will mute entirely. Using a value larger than 127 will result in undefined behavior, as this will result in a negative scale factor. By default, this will be set to 100%. + +This scaling factor is only used if flag 0x20 is set in the sequence player's mute behavior. + +**Parameters:** +* `numerator` [integer: 0-127] - The number to divide by 127 + +**Example:** +``` +mutebhv 0x20 # Sets mute behavior to reduce sequence volume when muted +mutescale 40 # Reduce volume by 31.5% when muted +ldchan 1, chan1 # Play channel 1 at 100% volume +delay 500 +mute # Channel 1 continues playing at 31.5% volume +``` + +**initchan** *mask* + +**Description:** Initializes the indicated channels on the sequence player and prepares them for playing audio. This configure's the channels with the default soundfont, assigned mute behavior, and configured note allocation policy. Each bit on the bitmask represents a different channel, with the most significant bit representing channel 16 and the least significant bit representing channel 1. + +It is not strictly necessary to use `initchan` for the channels to be used, however the previous mentioned settings will not be configured on the channel and will be in an undefined state. For obvious reasons, this is not recommended. + +**Parameters:** +* `mask` [integer: 0-65535] - The bitmask defining the channels to initialize. + +**Example:** +``` +mutebhv 0x20 +initchan 0b0000000100111110 +ldchan 1, chan1 +ldchan 2, chan2 +ldchan 3, chan3 +ldchan 4, chan4 +ldchan 5, chan5 +ldchan 8, chan8 +``` + +**fadescale** *numerator* + +**Description:** Specifies a scaling factor that should be applied to the final volume whenever the sequence is fading its volume. Similar to `mutescale`, the provided numerator is divided by `127` and then stored in the sequence player until fading is activated. Note that while it's possible to apply a value larger than 127, it will result in unusual behavior, as this byte is treated as signed and will result in a negative fraction. + +**Parameters:** +* `numerator` [integer: 0-127] - The number to divide by 127 + +**Example:** +``` +fadescale 89 # Sets the fade scale factor to 70% +volmode 1 # Sets the fade mode to gradual +vol 30 # Gradually fades to 23.6% +delay 100 +volmode 2 +``` + +**tempochg** *difference* + +**Description:** Applies a delta to the sequence's current tempo based on the parameter. The difference is treated as a signed byte and applied to the primary tempo on all subsequent ticks. Subsequent calls of `tempochg` will change the delta applied to the primary tempo. If the difference provided is 0, then the sequence will continue playing with the primary tempo. + +**Parameters:** +* `difference` [integer: -128-127] - The change to apply to the main tempo + +**Example:** +``` +tempo 80 # Sets primary tempo to 80 BPM +ldchan 1, chan1 +delay 400 +tempochg 20 # Temporarily brings the tempo up to 100 BPM +delay 400 +tempochg 0 # Returns the tempo back to 80 BPM +delay 400 +``` + +**tempo** *tempo* + +**Description:** Sets the primary tempo for the sequence. If the tempo provided is 0, it will be set to 1 instead. If the tempo is larger than the maximum tempo supported by the sequence player, it will be reduced to the highest tempo possible. + +**Parameters:** +* `tempo` [integer: 0-255] - The primary tempo for the sequence + +**Example:** +``` +tempo 60 # Sets primary tempo to 60 BPM +ldchan 1, chan1 +delay 100 # Plays for 100 ticks, or approximately 2 beats +``` + +**rtranspose** *transposition* + +**Description:** Applies a relative transposition for notes played on all channels on this sequence player. Subsequent calls of this command will continue to add the provided transposition to the current transposition on the sequence player. By default, the sequence player's transposition is set to 0. + +The player's transposition is stored as a 16-bit signed integer. If you apply a transposition that's larger than 32767, this will result in an integer overflow. In practice, this should not be an issue. + +Sequence transpositions are ignored by drum and sound effects. + +**Parameters:** +* `transposition` [integer: -128-127] - The relative change to apply to the current transposition + +**Example:** +``` +transpose 10 # Transposes the notes played up by 10 semitones +delay 50 +rtranspose -5 # Changes the transposition to 5 semitones above base +delay 50 +``` + +**transpose** *transposition* + +**Description:** Applies a transposition for notes played on all channels on this sequence player. Unlike `rtranspose`, this forces the transposition to the number of semitones. By default, the sequence player's transposition is set to 0. + +The player's transposition is stored as a 16-bit signed integer. If you apply a transposition that's larger than 32767, this will result in an integer overflow. In practice, this should not be an issue. + +Sequence transpositions are ignored by drum and sound effects. + +**Parameters:** +* `transposition` [integer: -128-127] - The number of semitones to transpose by + +**Example:** +``` +transpose 10 # Transposes the notes played up by 10 semitones +delay 50 +``` + +**freenotelist** + +**Description:** Frees the notes reserved on the sequence player and returns them back to the global note pool. + +It's recommended to avoid using this command while audio is playing for the sequence, as it can cause undefined behavior. + +**Parameters:** None. + +**Example:** +``` +ldchan 1, chan1 +ldchan 9, chan9 +delay 1500 +freenotelist # Frees any reserved notes on the sequence player. +``` + +**allocnotelist** *count* + +**Description:** Frees any reserved notes assigned to the sequence player, then reserves the number of notes requested for the sequence player. The notes in this pool can then be used by channels and note layers when needed, depending on the note allocation policy set. + +It's recommended to avoid using this command while audio is playing on the sequence, as this can result in undefined behavior. + +In general, it is not necessary to use this command, as by default the sequence player will use any free notes in the global note pool. This command also is not useful for addressing issues with notes cutting out on channels in a sequence, as this applies to the sequence player itself. Howver, it can be useful for preventing other sequences from stealing notes from this sequence. + +**Parameters:** +* `count` [integer: 0-255] - The number of notes to allocate. + +**Example:** +``` +allocnotelist 10 # Reserves 10 notes to the sequence. +ldchan 5, chan5 # Regardless of the number of effects or sequences playing, 10 notes will always +ldchan 6, chan6 # be able to play at any point. +delay 500 +freenotelist # Releases the reserved notes. +delay 500 # Now the player may not be able to play notes if there aren't enough in the + # global pool. +``` + +#### Channel Subsections + +##### Channel Registers + +Every channel contains two registers that instructions can use for mathematical calculations, loading and storing values, and referencing data sections. Like the sequence player, there is an eight-bit `$V` register that's used mainly for loading and storing values, and a sixteen-bit `$P` register used as an offset pointer for indirect references within the channel script. + +##### IO Ports + +Similar to the sequence player, each channel contains its own dedicated eight IO ports that are one byte wide. These ports can be used to store or communicate values across different portions of the channel script. + +Channels also have access to the sequence player's IO ports, allowing values to be sent across different levels as needed. Keep in mind that since each channel's script runs in parallel, you will want to ensure that channels do not write back to the same IO port on the sequence player in a destructive fashion. (These instructions are executed in a single thread, so it is safe for different channels to modify the same IO port if, for example, the script was configured to modify one bit while leaving the rest unmodified.) + +##### Metainstructions + +**.channel** *label name* + +**Description:** Defines a label for the following subsection of channel instructions. Note that it is considered an error if a channel label is proceeded with anything that is not a channel command. + +**Example:** +``` +.channel loop_start +ldlayer 1, legatobar +delay 500 +jump loop_start # Plays the same melody indefinitely. +``` + +##### Instructions + +| | 00 | 10 | 20 | 30 | 40 | 50 | 60 | 70 | 80 | 90 | A0 | B0 | C0 | D0 | E0 | F0 | +| -- | ------ | --------- | ------ | ----- | ----- | ----- | ---- | -------- | --------- | ---------- | -- | ----------- | ------------ | ----------- | ------------ | ------------- | +| 00 | cdelay | sample | ldchan | stcio | ldcio | subio | ldio | stio | testlayer | freelayer | | filter | | effects | volexp | freenotelist | +| 01 | cdelay | sample | ldchan | stcio | ldcio | subio | ldio | stio | testlayer | freelayer | | freefilter | instr | notealloc | vibfreqgrad | allocnotelist | +| 02 | cdelay | sample | ldchan | stcio | ldcio | subio | ldio | stio | testlayer | freelayer | | ldseqtoptr | dyntbl | sustain | vibdepthgrad | *rbltz | +| 03 | cdelay | sample | ldchan | stcio | ldcio | subio | ldio | stio | testlayer | freelayer | | ldfilter | short | bend | vibdelay | *rbeqz | +| 04 | cdelay | sample | ldchan | stcio | ldcio | subio | ldio | stio | testlayer | freelayer | | ptrtodyntbl | noshort | reverb | dyncall | *rjump | +| 05 | cdelay | sample | ldchan | stcio | ldcio | subio | ldio | stio | testlayer | freelayer | | dyntbltoptr | dyntbllookup | | rvrbidx | *bgez | +| 06 | cdelay | sample | ldchan | stcio | ldcio | subio | ldio | stio | testlayer | freelayer | | dyntblv | font | | samplbook | *break | +| 07 | cdelay | sample | ldchan | stcio | ldcio | subio | ldio | stio | testlayer | freelayer | | randtoptr | stseq | vibfreq | ldparams | *loopend | +| 08 | cdelay | sampleptr | ldchan | stcio | ldcio | subio | ldio | rldlayer | ldlayer | dynldlayer | | randvel | sub | vibdepth | params | *loop | +| 09 | cdelay | sampleptr | ldchan | stcio | ldcio | subio | ldio | rldlayer | ldlayer | dynldlayer | | randgate | and | releaserate | notepri | *bltz | +| 0A | cdelay | sampleptr | ldchan | stcio | ldcio | subio | ldio | rldlayer | ldlayer | dynldlayer | | | mutebhv | env | stop | *beqz | +| 0B | cdelay | sampleptr | ldchan | stcio | ldcio | subio | ldio | rldlayer | ldlayer | dynldlayer | | ptradd | ldseq | transpose | fontinstr | *jump | +| 0C | cdelay | sampleptr | ldchan | stcio | ldcio | subio | ldio | rldlayer | ldlayer | dynldlayer | | randptr | ldi | panweight | reset | *call | +| 0D | cdelay | sampleptr | ldchan | stcio | ldcio | subio | ldio | rldlayer | ldlayer | dynldlayer | | instr | stopchan | pan | gain | *delay | +| 0E | cdelay | sampleptr | ldchan | stcio | ldcio | subio | ldio | rldlayer | ldlayer | dynldlayer | | | lditoptr | preqscale | bendfine | *delay1 | +| 0F | cdelay | sampleptr | ldchan | stcio | ldcio | subio | ldio | rldlayer | ldlayer | dynldlayer | | | stptrtoseq | vol | | *end | + +Instructions marked with an asterisk (\*) are documented in the section *Branching Instructions*. + +**cdelay** *ticks* + +**Description:** Delays processing of the channel script by the provided number of ticks (up to 16). A delay of 0 is effectively a no-op. + +This command is functionally identical to `delay`, with a reduced range and encoded as a single byte for better script compression. + +**Parameters:** +* `ticks` [integer: 0-15] - The number of ticks to delay further processing. + +**Example:** +``` +ldlayer 1, melody +ldlayer 2, harmony +vol 30 # Gradually fade in +cdelay 14 +vol 45 +cdelay 14 +vol 60 +cdelay 14 +vol 75 +``` + +**sample** *IO* + +**Description:** Loads \ No newline at end of file diff --git a/extract_assets.py b/extract_assets.py index 3548172c51c..e0dd65ad231 100755 --- a/extract_assets.py +++ b/extract_assets.py @@ -134,11 +134,13 @@ def main(): msgdis.extract_all_text(extract_text_path, extract_staff_text_path) xmlFiles = [] + ignorePaths = ['samples', 'sequences', 'soundfonts'] for currentPath, _, files in os.walk(os.path.join("assets", "xml")): - for file in files: - fullPath = os.path.join(currentPath, file) - if file.endswith(".xml"): - xmlFiles.append(fullPath) + if all(path not in currentPath for path in ignorePaths): + for file in files: + fullPath = os.path.join(currentPath, file) + if file.endswith(".xml"): + xmlFiles.append(fullPath) try: numCores = int(args.jobs or 0) diff --git a/include/sequence.inc b/include/sequence.inc new file mode 100644 index 00000000000..e2286e68b9d --- /dev/null +++ b/include/sequence.inc @@ -0,0 +1,190 @@ +# Cache Policies +.define CACHE_PERMANENT 0 +.define CACHE_PERSISTENT 1 +.define CACHE_TEMPORARY 2 +.define CACHE_ANY 3 +.define CACHE_ANYNOSYNC 4 + +# Hardcoded Instruments +.define FONTANY_INSTR_SFX 126 +.define FONTANY_INSTR_DRUM 127 +# (implemented via gWaveSamples[]) +.define FONTANY_INSTR_SAWTOOTH 128 +.define FONTANY_INSTR_TRIANGLE 129 +.define FONTANY_INSTR_SINE 130 +.define FONTANY_INSTR_SQUARE 131 +.define FONTANY_INSTR_NOISE 132 +.define FONTANY_INSTR_BELL 133 +.define FONTANY_INSTR_8PULSE 134 +.define FONTANY_INSTR_4PULSE 135 +.define FONTANY_INSTR_ASM_NOISE 136 + +# Instrument Notes +.define PITCH_A0 0 +.define PITCH_BF0 1 +.define PITCH_B0 2 +.define PITCH_C1 3 +.define PITCH_DF1 4 +.define PITCH_D1 5 +.define PITCH_EF1 6 +.define PITCH_E1 7 +.define PITCH_F1 8 +.define PITCH_GF1 9 +.define PITCH_G1 10 +.define PITCH_AF1 11 +.define PITCH_A1 12 +.define PITCH_BF1 13 +.define PITCH_B1 14 +.define PITCH_C2 15 +.define PITCH_DF2 16 +.define PITCH_D2 17 +.define PITCH_EF2 18 +.define PITCH_E2 19 +.define PITCH_F2 20 +.define PITCH_GF2 21 +.define PITCH_G2 22 +.define PITCH_AF2 23 +.define PITCH_A2 24 +.define PITCH_BF2 25 +.define PITCH_B2 26 +.define PITCH_C3 27 +.define PITCH_DF3 28 +.define PITCH_D3 29 +.define PITCH_EF3 30 +.define PITCH_E3 31 +.define PITCH_F3 32 +.define PITCH_GF3 33 +.define PITCH_G3 34 +.define PITCH_AF3 35 +.define PITCH_A3 36 +.define PITCH_BF3 37 +.define PITCH_B3 38 +.define PITCH_C4 39 +.define PITCH_DF4 40 +.define PITCH_D4 41 +.define PITCH_EF4 42 +.define PITCH_E4 43 +.define PITCH_F4 44 +.define PITCH_GF4 45 +.define PITCH_G4 46 +.define PITCH_AF4 47 +.define PITCH_A4 48 +.define PITCH_BF4 49 +.define PITCH_B4 50 +.define PITCH_C5 51 +.define PITCH_DF5 52 +.define PITCH_D5 53 +.define PITCH_EF5 54 +.define PITCH_E5 55 +.define PITCH_F5 56 +.define PITCH_GF5 57 +.define PITCH_G5 58 +.define PITCH_AF5 59 +.define PITCH_A5 60 +.define PITCH_BF5 61 +.define PITCH_B5 62 +.define PITCH_C6 63 +.define PITCH_DF6 64 +.define PITCH_D6 65 +.define PITCH_EF6 66 +.define PITCH_E6 67 +.define PITCH_F6 68 +.define PITCH_GF6 69 +.define PITCH_G6 70 +.define PITCH_AF6 71 +.define PITCH_A6 72 +.define PITCH_BF6 73 +.define PITCH_B6 74 +.define PITCH_C7 75 +.define PITCH_DF7 76 +.define PITCH_D7 77 +.define PITCH_EF7 78 +.define PITCH_E7 79 +.define PITCH_F7 80 +.define PITCH_GF7 81 +.define PITCH_G7 82 +.define PITCH_AF7 83 +.define PITCH_A7 84 +.define PITCH_BF7 85 +.define PITCH_B7 86 +.define PITCH_C8 87 +.define PITCH_DF8 88 +.define PITCH_D8 89 +.define PITCH_EF8 90 +.define PITCH_E8 91 +.define PITCH_F8 92 +.define PITCH_GF8 93 +.define PITCH_G8 94 +.define PITCH_AF8 95 +.define PITCH_A8 96 +.define PITCH_BF8 97 +.define PITCH_B8 98 +.define PITCH_C9 99 +.define PITCH_DF9 100 +.define PITCH_D9 101 +.define PITCH_EF9 102 +.define PITCH_E9 103 +.define PITCH_F9 104 +.define PITCH_GF9 105 +.define PITCH_G9 106 +.define PITCH_AF9 107 +.define PITCH_A9 108 +.define PITCH_BF9 109 +.define PITCH_B9 110 +.define PITCH_C10 111 +.define PITCH_DF10 112 +.define PITCH_D10 113 +.define PITCH_EF10 114 +.define PITCH_E10 115 +.define PITCH_F10 116 +.define PITCH_BFNEG1 117 +.define PITCH_BNEG1 118 +.define PITCH_C0 119 +.define PITCH_DF0 120 +.define PITCH_D0 121 +.define PITCH_EF0 122 +.define PITCH_E0 123 +.define PITCH_F0 124 +.define PITCH_GF0 125 +.define PITCH_G0 126 +.define PITCH_AF0 127 + +# Soundfont IDs +.define SOUNDFONT_SFX_1 0 +.define SOUNDFONT_SFX_2 1 +.define SOUNDFONT_AMBIENCE 2 +.define SOUNDFONT_ORCHESTRA 3 +.define SOUNDFONT_DEKU_TREE 4 +.define SOUNDFONT_MARKET 5 +.define SOUNDFONT_TITLE 6 +.define SOUNDFONT_JABU_JABU 7 +.define SOUNDFONT_KAKARIKO_CHILD 8 +.define SOUNDFONT_FAIRY_FOUNTAIN 9 +.define SOUNDFONT_FIRE_TEMPLE 10 +.define SOUNDFONT_DODONGO_CAVERN 11 +.define SOUNDFONT_FOREST_TEMPLE 12 +.define SOUNDFONT_LON_LON_RANCH 13 +.define SOUNDFONT_GORON_CITY 14 +.define SOUNDFONT_KOKIRI_FOREST 15 +.define SOUNDFONT_SPIRIT_TEMPLE 16 +.define SOUNDFONT_HORSE_RACE 17 +.define SOUNDFONT_WARP_SONGS 18 +.define SOUNDFONT_LEGENDS 19 +.define SOUNDFONT_MINIGAMES 20 +.define SOUNDFONT_ZORA_DOMAIN 21 +.define SOUNDFONT_SHOPS 22 +.define SOUNDFONT_ICE_CAVERN 23 +.define SOUNDFONT_SHADOW_TEMPLE 24 +.define SOUNDFONT_WATER_TEMPLE 25 +.define SOUNDFONT_UNKNOWN_1 26 +.define SOUNDFONT_GERUDO_VALLEY 27 +.define SOUNDFONT_LAKESIDE_LABORATORY 28 +.define SOUNDFONT_KOTAKE_KOUME_THEME 29 +.define SOUNDFONT_GANON_CASTLE_ORGAN 30 +.define SOUNDFONT_GANON_CASTLE 31 +.define SOUNDFONT_GANONDORF_BATTLE 32 +.define SOUNDFONT_ENDING_1 33 +.define SOUNDFONT_ENDING_2 34 +.define SOUNDFONT_GAME_OVER 35 +.define SOUNDFONT_OWL_THEME 36 +.define SOUNDFONT_UNKNOWN_2 37 diff --git a/include/z64audio.h b/include/z64audio.h index b08a6558ef9..0a1ac95cef3 100644 --- a/include/z64audio.h +++ b/include/z64audio.h @@ -54,6 +54,14 @@ typedef enum { /* 2 */ SAMPLE_TABLE } SampleBankTableType; +typedef enum { + /* 0 */ CACHE_LOAD_PERMANENT, + /* 1 */ CACHE_LOAD_PERSISTENT, + /* 2 */ CACHE_LOAD_TEMPORARY, + /* 3 */ CACHE_LOAD_EITHER, + /* 4 */ CACHE_LOAD_EITHER_NOSYNC +} AudioCacheLoadType; + typedef enum { /* 0 */ CACHE_TEMPORARY, /* 1 */ CACHE_PERSISTENT, @@ -122,13 +130,13 @@ typedef struct { /* 0x04 */ u32 end; /* 0x08 */ u32 count; /* 0x0C */ char unk_0C[0x4]; - /* 0x10 */ s16 predictorState[16]; // only exists if count != 0. 8-byte aligned + /* 0x10 */ s16 predictorState[16]; // The predictor output state for the first frame of the loop, only present if count > 0 } AdpcmLoop; // size = 0x30 (or 0x10) typedef struct { /* 0x00 */ s32 order; /* 0x04 */ s32 numPredictors; - /* 0x08 */ s16 book[1]; // size 8 * order * numPredictors. 8-byte aligned + /* 0x08 */ s16 book[1]; // Predictor coefficients, where book is a variable-length array, each book's length is 8 * order * npredictors. 8-byte aligned } AdpcmBook; // size >= 0x8 typedef struct { diff --git a/spec b/spec index 7265476c1b2..cb372a082af 100644 --- a/spec +++ b/spec @@ -122,18 +122,172 @@ endseg beginseg name "Audiobank" - address 0x10 // fake RAM address to avoid map lookup inaccuracies - include "build/baserom/Audiobank.o" + include "build/assets/soundfonts/0_Sound_Effects_1.o" + include "build/assets/soundfonts/1_Sound_Effects_2.o" + include "build/assets/soundfonts/2_Ambient_Sounds.o" + include "build/assets/soundfonts/3_Orchestra.o" + include "build/assets/soundfonts/4_Deku_Tree.o" + include "build/assets/soundfonts/5_Market.o" + include "build/assets/soundfonts/6_Title_Theme.o" + include "build/assets/soundfonts/7_Jabu_Jabu.o" + include "build/assets/soundfonts/8_Child_Kakariko_Village.o" + include "build/assets/soundfonts/9_Fairy_Fountain.o" + include "build/assets/soundfonts/10_Fire_Temple.o" + include "build/assets/soundfonts/11_Dodongos_Cavern.o" + include "build/assets/soundfonts/12_Forest_Temple.o" + include "build/assets/soundfonts/13_Lon_Lon_Ranch.o" + include "build/assets/soundfonts/14_Goron_City.o" + include "build/assets/soundfonts/15_Kokiri_Forest.o" + include "build/assets/soundfonts/16_Spirit_Temple.o" + include "build/assets/soundfonts/17_Horse_Race.o" + include "build/assets/soundfonts/18_Warp_Songs.o" + include "build/assets/soundfonts/19_Legends_of_Hyrule.o" + include "build/assets/soundfonts/20_Minigames.o" + include "build/assets/soundfonts/21_Zoras_Domain.o" + include "build/assets/soundfonts/22_Shops.o" + include "build/assets/soundfonts/23_Ice_Cavern.o" + include "build/assets/soundfonts/24_Shadow_Temple.o" + include "build/assets/soundfonts/25_Water_Temple.o" + include "build/assets/soundfonts/26_Unused.o" + include "build/assets/soundfonts/27_Gerudo_Valley.o" + include "build/assets/soundfonts/28_Lakeside_Laboratory.o" + include "build/assets/soundfonts/29_Kotake_and_Koumes_Theme.o" + include "build/assets/soundfonts/30_Ganons_Castle_Organ.o" + include "build/assets/soundfonts/31_Ganons_Castle.o" + include "build/assets/soundfonts/32_Ganondorfs_Battle.o" + include "build/assets/soundfonts/33_Ending_1.o" + include "build/assets/soundfonts/34_Ending_2.o" + include "build/assets/soundfonts/35_Game_Over.o" + include "build/assets/soundfonts/36_Kaepora_Gaeboras_Theme.o" + include "build/assets/soundfonts/37_Unused_Deku_Tree.o" + include "build/data/audio_pad.rodata.o" endseg beginseg name "Audioseq" - include "build/baserom/Audioseq.o" + include "build/assets/sequences/000_Sound_Effects.prg.o" + include "build/assets/sequences/001_Ambient_Effects.prg.o" + include "build/assets/sequences/002_Hyrule_Field_Program.prg.o" + include "build/assets/sequences/003_Hyrule_Field_Intro.o" + include "build/assets/sequences/004_Hyrule_Field_Segment_1.o" + include "build/assets/sequences/005_Hyrule_Field_Segment_2.o" + include "build/assets/sequences/006_Hyrule_Field_Segment_3.o" + include "build/assets/sequences/007_Hyrule_Field_Segment_4.o" + include "build/assets/sequences/008_Hyrule_Field_Segment_5.o" + include "build/assets/sequences/009_Hyrule_Field_Segment_6.o" + include "build/assets/sequences/010_Hyrule_Field_Segment_7.o" + include "build/assets/sequences/011_Hyrule_Field_Segment_8.o" + include "build/assets/sequences/012_Hyrule_Field_Segment_9.o" + include "build/assets/sequences/013_Hyrule_Field_Segment_10.o" + include "build/assets/sequences/014_Hyrule_Field_Segment_11.o" + include "build/assets/sequences/015_Hyrule_Field_Enemy_Intro.o" + include "build/assets/sequences/016_Hyrule_Field_Enemy_1.o" + include "build/assets/sequences/017_Hyrule_Field_Enemy_2.o" + include "build/assets/sequences/018_Hyrule_Field_Enemy_3.o" + include "build/assets/sequences/019_Hyrule_Field_Enemy_4.o" + include "build/assets/sequences/020_Hyrule_Field_Idle_1.o" + include "build/assets/sequences/021_Hyrule_Field_Idle_2.o" + include "build/assets/sequences/022_Hyrule_Field_Idle_3.o" + include "build/assets/sequences/023_Hyrule_Field_Idle_4.o" + include "build/assets/sequences/024_Dodongos_Cavern.o" + include "build/assets/sequences/025_Kakariko_Village_Adult.o" + include "build/assets/sequences/026_Battle.o" + include "build/assets/sequences/027_Boss_Battle.o" + include "build/assets/sequences/028_Inside_the_Deku_Tree.o" + include "build/assets/sequences/029_Market.o" + include "build/assets/sequences/030_Title_Theme.o" + include "build/assets/sequences/031_House.o" + include "build/assets/sequences/032_Game_Over.o" + include "build/assets/sequences/033_Boss_Defeated.o" + include "build/assets/sequences/034_Got_Key_Item.o" + include "build/assets/sequences/035_Ganondorf_Sting.o" + include "build/assets/sequences/036_Got_Heart_Container.o" + include "build/assets/sequences/037_Prelude_of_Light.o" + include "build/assets/sequences/038_Inside_Jabu_Jabus_Belly.o" + include "build/assets/sequences/039_Kakariko_Village_Child.o" + include "build/assets/sequences/040_Fairy_Fountain.o" + include "build/assets/sequences/041_Zeldas_Theme.o" + include "build/assets/sequences/042_Fire_Temple.o" + include "build/assets/sequences/043_Anticipating_Treasure.o" + include "build/assets/sequences/044_Forest_Temple.o" + include "build/assets/sequences/045_Hyrule_Castle_Courtyard.o" + include "build/assets/sequences/046_Ganondorf_Theme_Organ.o" + include "build/assets/sequences/047_Lon_Lon_Ranch.o" + include "build/assets/sequences/048_Goron_City.o" + include "build/assets/sequences/049_Hyrule_Field_Morning.o" + include "build/assets/sequences/050_Got_Spiritual_Stone.o" + include "build/assets/sequences/051_Bolero_of_Fire.o" + include "build/assets/sequences/052_Minuet_of_Forest.o" + include "build/assets/sequences/053_Serenade_of_Water.o" + include "build/assets/sequences/054_Requiem_of_Spirit.o" + include "build/assets/sequences/055_Nocturne_of_Shadow.o" + include "build/assets/sequences/056_Mini_Boss_Battle.o" + include "build/assets/sequences/057_Got_Item.o" + include "build/assets/sequences/058_Temple_of_Time.o" + include "build/assets/sequences/059_Rescued_Epona.o" + include "build/assets/sequences/060_Kokiri_Forest.o" + include "build/assets/sequences/061_Got_Fairy_Ocarina.o" + include "build/assets/sequences/062_Lost_Woods.o" + include "build/assets/sequences/063_Spirit_Temple.o" + include "build/assets/sequences/064_Horse_Minigame.o" + include "build/assets/sequences/065_Horse_Minigame_Goal.o" + include "build/assets/sequences/066_Ingos_Theme.o" + include "build/assets/sequences/067_Got_Medallion.o" + include "build/assets/sequences/068_Sarias_Song.o" + include "build/assets/sequences/069_Eponas_Song.o" + include "build/assets/sequences/070_Zeldas_Lullaby.o" + include "build/assets/sequences/071_Suns_Song.o" + include "build/assets/sequences/072_Song_of_Time.o" + include "build/assets/sequences/073_Song_of_Storms.o" + include "build/assets/sequences/074_Navi_in_Flight.o" + include "build/assets/sequences/075_Deku_Tree_Theme.o" + include "build/assets/sequences/076_Windmill.o" + include "build/assets/sequences/077_Legends_of_Hyrule.o" + include "build/assets/sequences/078_Game_Shops.o" + include "build/assets/sequences/079_Sheiks_Theme.o" + include "build/assets/sequences/080_Zoras_Domain.o" + include "build/assets/sequences/081_Zelda_Sting.o" + include "build/assets/sequences/082_Zeldas_Theme_Ending.o" + include "build/assets/sequences/083_Got_Master_Sword.o" + include "build/assets/sequences/084_Ganondorfs_Theme.o" + include "build/assets/sequences/085_Shop.o" + include "build/assets/sequences/086_Chamber_of_Sages.o" + include "build/assets/sequences/088_Ice_Cavern.o" + include "build/assets/sequences/089_Opening_the_Door_of_Time.o" + include "build/assets/sequences/090_Kaepora_Gaeboras_Theme.o" + include "build/assets/sequences/091_Shadow_Temple.o" + include "build/assets/sequences/092_Water_Temple.o" + include "build/assets/sequences/093_The_Sages_Bridge.o" + include "build/assets/sequences/094_Seal_of_the_Six_Sages.o" + include "build/assets/sequences/095_Gerudo_Valley.o" + include "build/assets/sequences/096_Potion_Shop.o" + include "build/assets/sequences/097_Koume_and_Kotakes_Theme.o" + include "build/assets/sequences/098_Escape_from_Ganons_Castle.o" + include "build/assets/sequences/099_Ganondorfs_Castle.o" + include "build/assets/sequences/100_Ganondorf_Battle.o" + include "build/assets/sequences/101_Ganon_Battle.o" + include "build/assets/sequences/102_Ending_Credits_1.o" + include "build/assets/sequences/103_Ending_Credits_2.o" + include "build/assets/sequences/104_Ending_Credits_3.o" + include "build/assets/sequences/105_Ending_Credits_4.o" + include "build/assets/sequences/106_Ending_Credits_5.o" + include "build/assets/sequences/107_Dodongo_and_Volvagia_Battle.o" + include "build/assets/sequences/108_Timed_Minigame.o" + include "build/assets/sequences/109_Cutscene_Effects.prg.o" + /*include "build/assets/sequences/110_Trip_to_Skye.o" + include "build/assets/sequences/111_Lothlorien.o" + include "build/assets/sequences/112_FF6_Overworld.o" + include "build/assets/sequences/113_FF7_Airship.o"*/ endseg beginseg name "Audiotable" - include "build/baserom/Audiotable.o" + include "build/assets/samplebanks/0_Sound_Effects.o" + include "build/assets/samplebanks/2_Inside_the_Deku_Tree.o" + include "build/assets/samplebanks/3_Inside_Jabu_Jabu.o" + include "build/assets/samplebanks/4_Forest_Temple__Unused_.o" + include "build/assets/samplebanks/5_Goron_City.o" + include "build/assets/samplebanks/6_Spirit_Temple.o" endseg beginseg @@ -517,7 +671,10 @@ beginseg include_data_with_rodata "build/src/code/z_message_PAL.o" include "build/src/code/z_game_over.o" include "build/src/code/z_construct.o" - include "build/data/audio_tables.rodata.o" + include_data_with_rodata "build/assets/data/SoundFontTable.o" + include_data_with_rodata "build/assets/data/SequenceFontTable.o" + include_data_with_rodata "build/assets/data/SequenceTable.o" + include_data_with_rodata "build/assets/data/SampleBankTable.o" include "build/data/rsp.text.o" include "build/data/rsp.rodata.o" endseg diff --git a/src/code/audio_seqplayer.c b/src/code/audio_seqplayer.c index 1bf38419bb7..ca418b92da3 100644 --- a/src/code/audio_seqplayer.c +++ b/src/code/audio_seqplayer.c @@ -1733,7 +1733,7 @@ void AudioSeq_SequencePlayerProcessSequence(SequencePlayer* seqPlayer) { break; case 0xDD: - seqPlayer->tempo = AudioSeq_ScriptReadU8(seqScript) * 48; + seqPlayer->tempo = AudioSeq_ScriptReadU8(seqScript) * TATUMS_PER_BEAT; if (seqPlayer->tempo > gAudioContext.tempoInternalToExternal) { seqPlayer->tempo = (u16)gAudioContext.tempoInternalToExternal; } @@ -1743,7 +1743,7 @@ void AudioSeq_SequencePlayerProcessSequence(SequencePlayer* seqPlayer) { break; case 0xDC: - seqPlayer->unk_0C = (s8)AudioSeq_ScriptReadU8(seqScript) * 48; + seqPlayer->unk_0C = (s8)AudioSeq_ScriptReadU8(seqScript) * TATUMS_PER_BEAT; break; case 0xDA: diff --git a/tools/.gitignore b/tools/.gitignore index 4dff1be3aee..b3b10da5a85 100644 --- a/tools/.gitignore +++ b/tools/.gitignore @@ -6,6 +6,11 @@ mkdmadata mkldscript reloc_prereq vtxdis +aifc_decode +assemble_sequence +aiff_extract_codebook +tabledesign +vadpcm_enc yaz0 graphovl/ diff --git a/tools/Makefile b/tools/Makefile index 4d342e24859..582d0097bec 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -1,5 +1,7 @@ CFLAGS := -Wall -Wextra -pedantic -std=c99 -g -O2 -PROGRAMS := elf2rom makeromfs mkdmadata mkldscript reloc_prereq vtxdis yaz0 +PROGRAMS := aifc_decode elf2rom makeromfs mkdmadata mkldscript reloc_prereq vtxdis yaz0 +CPPFLAGS := -Wall -Wextra -pedantic -std=c++17 -g -O2 +CPP_PROGRAMS := assemble_sequence ifeq ($(shell command -v clang >/dev/null 2>&1; echo $$?),0) CC := clang @@ -30,18 +32,29 @@ distclean: clean .PHONY: all clean distclean -elf2rom_SOURCES := elf2rom.c elf32.c n64chksum.c util.c -makeromfs_SOURCES := makeromfs.c n64chksum.c util.c -mkdmadata_SOURCES := mkdmadata.c spec.c util.c -mkldscript_SOURCES := mkldscript.c spec.c util.c -reloc_prereq_SOURCES := reloc_prereq.c spec.c util.c -vtxdis_SOURCES := vtxdis.c -yaz0_SOURCES := yaz0tool.c yaz0.c util.c +aifc_decode_SOURCES := aifc_decode.c +assemble_sequence_SOURCES := assemble_sequence.cpp +elf2rom_SOURCES := elf2rom.c elf32.c n64chksum.c util.c +makeromfs_SOURCES := makeromfs.c n64chksum.c util.c +mkdmadata_SOURCES := mkdmadata.c spec.c util.c +mkldscript_SOURCES := mkldscript.c spec.c util.c +reloc_prereq_SOURCES := reloc_prereq.c spec.c util.c +vtxdis_SOURCES := vtxdis.c +yaz0_SOURCES := yaz0tool.c yaz0.c util.c +aifc_decode_LIBRARIES := -lm +assemble_sequence_LIBRARIES := -lstdc++ -lm define COMPILE = $(1): $($1_SOURCES) - $(CC) $(CFLAGS) $$^ -o $$@ + $(CC) $(CFLAGS) -o $$@ $$^ $($1_LIBRARIES) +endef + +define CPPCOMPILE = +$(1): $($1_SOURCES) + $(CC) $(CPPFLAGS) -o $$@ $$^ $($1_LIBRARIES) endef $(foreach p,$(PROGRAMS),$(eval $(call COMPILE,$(p)))) + +$(foreach p,$(CPP_PROGRAMS),$(eval $(call CPPCOMPILE,$(p)))) diff --git a/tools/aifc_decode.c b/tools/aifc_decode.c new file mode 100644 index 00000000000..94a62dfca34 --- /dev/null +++ b/tools/aifc_decode.c @@ -0,0 +1,1035 @@ +/** + * Bruteforcing decoder for converting ADPCM-encoded AIFC into AIFF, in a way + * that roundtrips with vadpcm_enc. + */ +#include +#include +#include +#include +#include +#include +#include + +typedef signed char s8; +typedef short s16; +typedef int s32; +typedef long long s64; +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; +typedef unsigned long long u64; +typedef float f32; +typedef double f64; + +#define bswap16(x) __builtin_bswap16(x) +#define bswap32(x) __builtin_bswap32(x) +#define BSWAP16(x) x = __builtin_bswap16(x) +#define BSWAP32(x) x = __builtin_bswap32(x) +#define BSWAP16_MANY(x, n) for (s32 _i = 0; _i < n; _i++) BSWAP16((x)[_i]) + +#define NORETURN __attribute__((noreturn)) +#define UNUSED __attribute__((unused)) + +typedef struct { + u32 ckID; + u32 ckSize; +} ChunkHeader; + +typedef struct { + u32 ckID; + u32 ckSize; + u32 formType; +} Chunk; + +typedef struct { + s16 numChannels; + u16 numFramesH; + u16 numFramesL; + s16 sampleSize; + s16 sampleRate[5]; // 80-bit float + u16 compressionTypeH; + u16 compressionTypeL; +} CommonChunk; + +typedef struct { + s16 MarkerID; + u16 positionH; + u16 positionL; +} Marker; + +typedef struct { + s16 playMode; + s16 beginLoop; + s16 endLoop; +} Loop; + +typedef struct { + s8 baseNote; + s8 detune; + s8 lowNote; + s8 highNote; + s8 lowVelocity; + s8 highVelocity; + s16 gain; + Loop sustainLoop; + Loop releaseLoop; +} InstrumentChunk; + +typedef struct { + s32 offset; + s32 blockSize; +} SoundDataChunk; + +typedef struct { + s16 version; + s16 order; + s16 nEntries; +} CodeChunk; + +typedef struct { + u32 start; + u32 end; + u32 count; + s16 state[16]; +} ALADPCMloop; + + +static char usage[] = "input.aifc output.aiff"; +static const char *progname, *infilename; +static int framesize = 9; + +#define checked_fread(a, b, c, d) if (fread(a, b, c, d) != c) fail_parse("error parsing file") + +NORETURN +void fail_parse(const char *fmt, ...) +{ + char *formatted = NULL; + va_list ap; + va_start(ap, fmt); + int size = vsnprintf(NULL, 0, fmt, ap); + va_end(ap); + if (size >= 0) { + size++; + formatted = malloc(size); + if (formatted != NULL) { + va_start(ap, fmt); + size = vsnprintf(formatted, size, fmt, ap); + va_end(ap); + if (size < 0) { + free(formatted); + formatted = NULL; + } + } + } + + if (formatted != NULL) { + fprintf(stderr, "%s: %s [%s]\n", progname, formatted, infilename); + free(formatted); + } + exit(1); +} + +s32 myrand() +{ + static u64 state = 1619236481962341ULL; + state *= 3123692312237ULL; + state += 1; + return state >> 33; +} + +s16 qsample(f32 x, s32 scale) +{ + if (x > 0.0f) { + return (s16) ((x / scale) + 0.4999999); + } else { + return (s16) ((x / scale) - 0.4999999); + } +} + +void clamp_to_s16(f32 *in, s32 *out) +{ + f32 llevel = -0x8000; + f32 ulevel = 0x7fff; + + for (s32 i = 0; i < 16; i++) { + if (in[i] > ulevel) in[i] = ulevel; + if (in[i] < llevel) in[i] = llevel; + + if (in[i] > 0.0f) { + out[i] = (s32) (in[i] + 0.5); + } else { + out[i] = (s32) (in[i] - 0.5); + } + } +} + +s16 clamp_bits(s32 x, s32 bits) +{ + s32 lim = 1 << (bits - 1); + if (x < -lim) return -lim; + if (x > lim - 1) return lim - 1; + return x; +} + +s32 readaifccodebook(FILE *fhandle, s32 ****table, s16 *order, s16 *npredictors) +{ + checked_fread(order, sizeof(s16), 1, fhandle); + BSWAP16(*order); + checked_fread(npredictors, sizeof(s16), 1, fhandle); + BSWAP16(*npredictors); + *table = malloc(*npredictors * sizeof(s32 **)); + for (s32 i = 0; i < *npredictors; i++) { + (*table)[i] = malloc(8 * sizeof(s32 *)); + for (s32 j = 0; j < 8; j++) { + (*table)[i][j] = malloc((*order + 8) * sizeof(s32)); + } + } + + for (s32 i = 0; i < *npredictors; i++) { + s32 **table_entry = (*table)[i]; + for (s32 j = 0; j < *order; j++) { + for (s32 k = 0; k < 8; k++) { + s16 ts; + checked_fread(&ts, sizeof(s16), 1, fhandle); + BSWAP16(ts); + table_entry[k][j] = ts; + } + } + + for (s32 k = 1; k < 8; k++) { + table_entry[k][*order] = table_entry[k - 1][*order - 1]; + } + + table_entry[0][*order] = 1 << 11; + + for (s32 k = 1; k < 8; k++) { + s32 j = 0; + for (; j < k; j++) { + table_entry[j][k + *order] = 0; + } + + for (; j < 8; j++) { + table_entry[j][k + *order] = table_entry[j - k][*order]; + } + } + } + return 0; +} + +ALADPCMloop *readlooppoints(FILE *ifile, s16 *nloops) +{ + checked_fread(nloops, sizeof(s16), 1, ifile); + BSWAP16(*nloops); + ALADPCMloop *al = malloc(*nloops * sizeof(ALADPCMloop)); + for (s32 i = 0; i < *nloops; i++) { + checked_fread(&al[i], sizeof(ALADPCMloop), 1, ifile); + BSWAP32(al[i].start); + BSWAP32(al[i].end); + BSWAP32(al[i].count); + BSWAP16_MANY(al[i].state, 16); + } + return al; +} + +s32 inner_product(s32 length, s32 *v1, s32 *v2) +{ + s32 out = 0; + for (s32 i = 0; i < length; i++) { + out += v1[i] * v2[i]; + } + + // Compute "out / 2^11", rounded down. + s32 dout = out / (1 << 11); + s32 fiout = dout * (1 << 11); + return dout - (out - fiout < 0); +} + +void my_decodeframe(u8 *frame, s32 *decompressed, s32 *state, s32 order, s32 ***coefTable) +{ + s32 ix[16]; + + u8 header = frame[0]; + s32 scale = 1 << (header >> 4); + s32 optimalp = header & 0xf; + + if (framesize == 5) { + for (s32 i = 0; i < 16; i += 4) { + u8 c = frame[1 + i/4]; + ix[i] = c >> 6; + ix[i + 1] = (c >> 4) & 0x3; + ix[i + 2] = (c >> 2) & 0x3; + ix[i + 3] = c & 0x3; + } + } else { + for (s32 i = 0; i < 16; i += 2) { + u8 c = frame[1 + i/2]; + ix[i] = c >> 4; + ix[i + 1] = c & 0xf; + } + } + + for (s32 i = 0; i < 16; i++) { + if (framesize == 5) { + if (ix[i] >= 2) ix[i] -= 4; + } else { + if (ix[i] >= 8) ix[i] -= 16; + } + decompressed[i] = ix[i]; + ix[i] *= scale; + } + + for (s32 j = 0; j < 2; j++) { + s32 in_vec[16]; + if (j == 0) { + for (s32 i = 0; i < order; i++) { + in_vec[i] = state[16 - order + i]; + } + } else { + for (s32 i = 0; i < order; i++) { + in_vec[i] = state[8 - order + i]; + } + } + + for (s32 i = 0; i < 8; i++) { + s32 ind = j * 8 + i; + in_vec[order + i] = ix[ind]; + state[ind] = inner_product(order + i, coefTable[optimalp][i], in_vec) + ix[ind]; + } + } +} + +void my_encodeframe(u8 *out, s16 *inBuffer, s32 *origState, s32 ***coefTable, s32 order, s32 npredictors) +{ + s16 ix[16]; + s32 prediction[16]; + s32 inVector[16]; + s32 optimalp = 0; + s32 scale; + s32 encBits = (framesize == 5 ? 2 : 4); + s32 llevel = -(1 << (encBits - 1)); + s32 ulevel = -llevel - 1; + s32 ie[16]; + f32 e[16]; + f32 min = 1e30; + s32 scaleFactor = 16 - encBits; + + for (s32 k = 0; k < npredictors; k++) { + for (s32 j = 0; j < 2; j++) { + for (s32 i = 0; i < order; i++) { + inVector[i] = (j == 0 ? origState[16 - order + i] : inBuffer[8 - order + i]); + } + + for (s32 i = 0; i < 8; i++) { + prediction[j * 8 + i] = inner_product(order + i, coefTable[k][i], inVector); + inVector[i + order] = inBuffer[j * 8 + i] - prediction[j * 8 + i]; + e[j * 8 + i] = (f32) inVector[i + order]; + } + } + + f32 se = 0.0f; + for (s32 j = 0; j < 16; j++) { + se += e[j] * e[j]; + } + + if (se < min) { + min = se; + optimalp = k; + } + } + + for (s32 j = 0; j < 2; j++) { + for (s32 i = 0; i < order; i++) { + inVector[i] = (j == 0 ? origState[16 - order + i] : inBuffer[8 - order + i]); + } + + for (s32 i = 0; i < 8; i++) { + prediction[j * 8 + i] = inner_product(order + i, coefTable[optimalp][i], inVector); + e[j * 8 + i] = inVector[i + order] = inBuffer[j * 8 + i] - prediction[j * 8 + i]; + } + } + + clamp_to_s16(e, ie); + + s32 max = 0; + for (s32 i = 0; i < 16; i++) { + if (abs(ie[i]) > abs(max)) { + max = ie[i]; + } + } + + for (scale = 0; scale <= scaleFactor; scale++) { + if (max <= ulevel && max >= llevel) break; + max /= 2; + } + + s32 state[16]; + for (s32 i = 0; i < 16; i++) { + state[i] = origState[i]; + } + + s32 nIter, again; + for (nIter = 0, again = 1; nIter < 2 && again; nIter++) { + again = 0; + if (nIter == 1) scale++; + if (scale > scaleFactor) { + scale = scaleFactor; + } + + for (s32 j = 0; j < 2; j++) { + s32 base = j * 8; + for (s32 i = 0; i < order; i++) { + inVector[i] = (j == 0 ? + origState[16 - order + i] : state[8 - order + i]); + } + + for (s32 i = 0; i < 8; i++) { + prediction[base + i] = inner_product(order + i, coefTable[optimalp][i], inVector); + f32 se = (f32) inBuffer[base + i] - (f32) prediction[base + i]; + ix[base + i] = qsample(se, 1 << scale); + s32 cV = clamp_bits(ix[base + i], encBits) - ix[base + i]; + if (cV > 1 || cV < -1) again = 1; + ix[base + i] += cV; + inVector[i + order] = ix[base + i] * (1 << scale); + state[base + i] = prediction[base + i] + inVector[i + order]; + } + } + } + + u8 header = (scale << 4) | (optimalp & 0xf); + out[0] = header; + if (framesize == 5) { + for (s32 i = 0; i < 16; i += 4) { + u8 c = ((ix[i] & 0x3) << 6) | ((ix[i + 1] & 0x3) << 4) | ((ix[i + 2] & 0x3) << 2) | (ix[i + 3] & 0x3); + out[1 + i/4] = c; + } + } else { + for (s32 i = 0; i < 16; i += 2) { + u8 c = ((ix[i] & 0xf) << 4) | (ix[i + 1] & 0xf); + out[1 + i/2] = c; + } + } +} + +void permute(s32 *out, s32 *in, s32 *decompressed, s32 scale) +{ + int normal = myrand() % 3 == 0; + for (s32 i = 0; i < 16; i++) { + s32 lo = in[i] - scale / 2; + s32 hi = in[i] + scale / 2; + if (framesize == 9) { + if (decompressed[i] == -8 && myrand() % 10 == 0) lo -= scale * 3/2; + else if (decompressed[i] == 7 && myrand() % 10 == 0) hi += scale * 3/2; + } + else if (decompressed[i] == -2 && myrand() % 7 == 0) lo -= scale * 3/2; + else if (decompressed[i] == 1 && myrand() % 10 == 0) hi += scale * 3/2; + else if (normal) {} + else if (decompressed[i] == 0) { + if (myrand() % 3) { + lo = in[i] - scale / 5; + hi = in[i] + scale / 5; + } + else if (myrand() % 2) { + lo = in[i] - scale / 3; + hi = in[i] + scale / 3; + } + } + else if (myrand() % 3) { + if (decompressed[i] < 0) lo = in[i] + scale / 4; + if (decompressed[i] > 0) hi = in[i] - scale / 4; + } + else if (myrand() % 2) { + if (decompressed[i] < 0) lo = in[i] - scale / 4; + if (decompressed[i] > 0) hi = in[i] + scale / 4; + } + out[i] = clamp_bits(lo + myrand() % (hi - lo + 1), 16); + } +} + +void get_bounds(s32 *in, s32 *decompressed, s32 scale, s32 *minVals, s32 *maxVals) +{ + s32 minv, maxv; + if (framesize == 9) { + minv = -8; + maxv = 7; + } else { + minv = -2; + maxv = 1; + } + for (s32 i = 0; i < 16; i++) { + s32 lo = in[i] - scale / 2; + s32 hi = in[i] + scale / 2; + lo -= scale; + hi += scale; + if (decompressed[i] == minv) lo -= scale; + else if (decompressed[i] == maxv) hi += scale; + minVals[i] = lo; + maxVals[i] = hi; + } +} + +s64 scored_encode(s32 *inBuffer, s32 *origState, s32 ***coefTable, s32 order, s32 npredictors, s32 wantedPredictor, s32 wantedScale, s32 wantedIx[16]) +{ + s32 prediction[16]; + s32 inVector[16]; + s32 optimalp = 0; + s32 scale; + s32 encBits = (framesize == 5 ? 2 : 4); + s32 llevel = -(1 << (encBits - 1)); + s32 ulevel = -llevel - 1; + s32 ie[16]; + f32 e[16]; + f32 min = 1e30; + s32 scaleFactor = 16 - encBits; + f32 errs[4]; + s64 scoreA = 0, scoreB = 0, scoreC = 0; + + for (s32 k = 0; k < npredictors; k++) { + for (s32 j = 0; j < 2; j++) { + for (s32 i = 0; i < order; i++) { + inVector[i] = (j == 0 ? origState[16 - order + i] : inBuffer[8 - order + i]); + } + + for (s32 i = 0; i < 8; i++) { + prediction[j * 8 + i] = inner_product(order + i, coefTable[k][i], inVector); + inVector[i + order] = inBuffer[j * 8 + i] - prediction[j * 8 + i]; + e[j * 8 + i] = (f32) inVector[i + order]; + } + } + + f32 se = 0.0f; + for (s32 j = 0; j < 16; j++) { + se += e[j] * e[j]; + } + + errs[k] = se; + + if (se < min) { + min = se; + optimalp = k; + } + } + + for (s32 k = 0; k < npredictors; k++) { + if (errs[k] < errs[wantedPredictor]) { + scoreA += (s64)(errs[wantedPredictor] - errs[k]); + } + } + if (optimalp != wantedPredictor) { + // probably penalized above, but add extra penalty in case the error + // values were the exact same + scoreA += 1; + } + optimalp = wantedPredictor; + + for (s32 j = 0; j < 2; j++) { + for (s32 i = 0; i < order; i++) { + inVector[i] = (j == 0 ? origState[16 - order + i] : inBuffer[8 - order + i]); + } + + for (s32 i = 0; i < 8; i++) { + prediction[j * 8 + i] = inner_product(order + i, coefTable[optimalp][i], inVector); + e[j * 8 + i] = inVector[i + order] = inBuffer[j * 8 + i] - prediction[j * 8 + i]; + } + } + + clamp_to_s16(e, ie); + + s32 max = 0; + for (s32 i = 0; i < 16; i++) { + if (abs(ie[i]) > abs(max)) { + max = ie[i]; + } + } + + for (scale = 0; scale <= scaleFactor; scale++) { + if (max <= ulevel && max >= llevel) break; + max /= 2; + } + + // Preliminary ix computation, computes whether scale needs to be incremented + s32 state[16]; + s32 again = 0; + for (s32 j = 0; j < 2; j++) { + s32 base = j * 8; + for (s32 i = 0; i < order; i++) { + inVector[i] = (j == 0 ? + origState[16 - order + i] : state[8 - order + i]); + } + + for (s32 i = 0; i < 8; i++) { + prediction[base + i] = inner_product(order + i, coefTable[optimalp][i], inVector); + f32 se = (f32) inBuffer[base + i] - (f32) prediction[base + i]; + s32 ix = qsample(se, 1 << scale); + s32 clampedIx = clamp_bits(ix, encBits); + s32 cV = clampedIx - ix; + if (cV > 1 || cV < -1) { + again = 1; + } + inVector[i + order] = clampedIx * (1 << scale); + state[base + i] = prediction[base + i] + inVector[i + order]; + } + } + + if (again && scale < scaleFactor) { + scale++; + } + + if (scale != wantedScale) { + // We could do math to penalize scale mismatches accurately, but it's + // simpler to leave it as a constraint by setting an infinite penalty. + scoreB += 100000000; + scale = wantedScale; + } + + // Then again for real, but now also with penalty computation + for (s32 j = 0; j < 2; j++) { + s32 base = j * 8; + for (s32 i = 0; i < order; i++) { + inVector[i] = (j == 0 ? + origState[16 - order + i] : state[8 - order + i]); + } + + for (s32 i = 0; i < 8; i++) { + prediction[base + i] = inner_product(order + i, coefTable[optimalp][i], inVector); + s64 ise = (s64) inBuffer[base + i] - (s64) prediction[base + i]; + f32 se = (f32) inBuffer[base + i] - (f32) prediction[base + i]; + s32 ix = qsample(se, 1 << scale); + s32 clampedIx = clamp_bits(ix, encBits); + s32 val = wantedIx[base + i] * (1 << scale); + if (clampedIx != wantedIx[base + i]) { + assert(ix != wantedIx[base + i]); + s32 lo = val - (1 << scale) / 2; + s32 hi = val + (1 << scale) / 2; + s64 diff = 0; + if (ise < lo) diff = lo - ise; + else if (ise > hi) diff = ise - hi; + scoreC += diff * diff + 1; + } + inVector[i + order] = val; + state[base + i] = prediction[base + i] + val; + } + } + + // Penalties for going outside s16 + for (s32 i = 0; i < 16; i++) { + s64 diff = 0; + if (inBuffer[i] < -0x8000) diff = -0x8000 - inBuffer[i]; + if (inBuffer[i] > 0x7fff) diff = inBuffer[i] - 0x7fff; + scoreC += diff * diff; + } + + return scoreA + scoreB + 10 * scoreC; +} + +s32 descent(s32 guess[16], s32 minVals[16], s32 maxVals[16], u8 input[9], s32 lastState[16], s32 ***coefTable, s32 order, s32 npredictors, s32 wantedPredictor, s32 wantedScale, s32 wantedIx[32]) +{ + const f64 inf = 1e100; + s64 curScore = scored_encode(guess, lastState, coefTable, order, npredictors, wantedPredictor, wantedScale, wantedIx); + for (;;) { + f64 delta[16]; + if (curScore == 0) { + return 1; + } + + // Compute gradient, and how far to move along it at most. + f64 maxMove = inf; + for (s32 i = 0; i < 16; i++) { + guess[i] += 1; + s64 scoreUp = scored_encode(guess, lastState, coefTable, order, npredictors, wantedPredictor, wantedScale, wantedIx); + guess[i] -= 2; + s64 scoreDown = scored_encode(guess, lastState, coefTable, order, npredictors, wantedPredictor, wantedScale, wantedIx); + guess[i] += 1; + if (scoreUp >= curScore && scoreDown >= curScore) { + // Don't touch this coordinate + delta[i] = 0; + } else if (scoreDown < scoreUp) { + if (guess[i] == minVals[i]) { + // Don't allow moving out of bounds + delta[i] = 0; + } else { + delta[i] = -(f64)(curScore - scoreDown); + maxMove = fmin(maxMove, (minVals[i] - guess[i]) / delta[i]); + } + } else { + if (guess[i] == maxVals[i]) { + delta[i] = 0; + } else { + delta[i] = (f64)(curScore - scoreUp); + maxMove = fmin(maxMove, (maxVals[i] - guess[i]) / delta[i]); + } + } + } + if (maxMove == inf || maxMove <= 0) { + return 0; + } + + // Try exponentially spaced candidates along the gradient. + s32 nguess[16]; + s32 bestGuess[16]; + s64 bestScore = curScore; + for (;;) { + s32 changed = 0; + for (s32 i = 0; i < 16; i++) { + nguess[i] = (s32)round(guess[i] + delta[i] * maxMove); + if (nguess[i] != guess[i]) changed = 1; + } + if (!changed) break; + s64 score = scored_encode(nguess, lastState, coefTable, order, npredictors, wantedPredictor, wantedScale, wantedIx); + if (score < bestScore) { + bestScore = score; + memcpy(bestGuess, nguess, sizeof(nguess)); + } + maxMove *= 0.7; + } + + if (bestScore == curScore) { + // No improvements along that line, give up. + return 0; + } + curScore = bestScore; + memcpy(guess, bestGuess, sizeof(bestGuess)); + } +} + +s32 bruteforce(s32 guess[16], u8 input[9], s32 decoded[16], s32 decompressed[16], s32 lastState[16], s32 ***coefTable, s32 order, s32 npredictors) +{ + s32 scale = input[0] >> 4, predictor = input[0] & 0xF; + + s32 minVals[16], maxVals[16]; + get_bounds(decoded, decompressed, 1 << scale, minVals, maxVals); + + for (;;) { + s64 bestScore = -1; + s32 bestGuess[16]; + for (s32 it = 0; it < 100; it++) { + permute(guess, decoded, decompressed, 1 << scale); + s64 score = scored_encode(guess, lastState, coefTable, order, npredictors, predictor, scale, decompressed); + if (score == 0) { + return 1; + } + if (bestScore == -1 || score < bestScore) { + bestScore = score; + memcpy(bestGuess, guess, sizeof(bestGuess)); + } + } + memcpy(guess, bestGuess, sizeof(bestGuess)); + if (descent(guess, minVals, maxVals, input, lastState, coefTable, order, npredictors, predictor, scale, decompressed)) { + return 1; + } + } +} + +void write_header(FILE *ofile, const char *id, s32 size) +{ + fwrite(id, 4, 1, ofile); + BSWAP32(size); + fwrite(&size, sizeof(s32), 1, ofile); +} + +int main(int argc, char **argv) +{ + s16 order = -1; + s16 nloops = 0; + ALADPCMloop *aloops = NULL; + s16 npredictors = -1; + s32 ***coefTable = NULL; + s32 state[16]; + s32 decompressed[16]; + s32 soundPointer = -1; + s32 currPos = 0; + s32 nSamples = 0; + Chunk FormChunk; + ChunkHeader Header; + CommonChunk CommChunk; + InstrumentChunk InstChunk; + SoundDataChunk SndDChunk; + FILE *ifile; + FILE *ofile; + progname = argv[0]; + + if (argc < 3) { + fprintf(stderr, "%s %s\n", progname, usage); + exit(1); + } + + infilename = argv[1]; + + if ((ifile = fopen(infilename, "rb")) == NULL) { + fail_parse("AIFF-C file could not be opened"); + exit(1); + } + + if ((ofile = fopen(argv[2], "wb")) == NULL) { + fprintf(stderr, "%s: output file could not be opened [%s]\n", progname, argv[2]); + exit(1); + } + + memset(&InstChunk, 0, sizeof(InstChunk)); + + checked_fread(&FormChunk, sizeof(FormChunk), 1, ifile); + BSWAP32(FormChunk.ckID); + BSWAP32(FormChunk.formType); + if ((FormChunk.ckID != 0x464f524d) || (FormChunk.formType != 0x41494643)) { // FORM, AIFC + fail_parse("not an AIFF-C file"); + } + + for (;;) { + s32 num = fread(&Header, sizeof(Header), 1, ifile); + u32 ts; + if (num <= 0) break; + BSWAP32(Header.ckID); + BSWAP32(Header.ckSize); + + Header.ckSize++; + Header.ckSize &= ~1; + s32 offset = ftell(ifile); + + switch (Header.ckID) { + case 0x434f4d4d: // COMM + checked_fread(&CommChunk, sizeof(CommChunk), 1, ifile); + BSWAP16(CommChunk.numChannels); + BSWAP16(CommChunk.numFramesH); + BSWAP16(CommChunk.numFramesL); + BSWAP16(CommChunk.sampleSize); + BSWAP16(CommChunk.compressionTypeH); + BSWAP16(CommChunk.compressionTypeL); + s32 cType = (CommChunk.compressionTypeH << 16) + CommChunk.compressionTypeL; + if (cType == 0x56415043 || cType == 0x41445039) { // VAPC or ADP9 + framesize = 9; + } else if (cType == 0x41445035) { // ADP5 + framesize = 5; + } else if (cType == 0x4850434d) { // HPCM + framesize = 16; + } else { + char comprType[5] = { + CommChunk.compressionTypeH >> 8, + CommChunk.compressionTypeH & 0xFF, + CommChunk.compressionTypeL >> 8, + CommChunk.compressionTypeL & 0xFF, + 0 + }; + fail_parse("file is of the wrong compression type [got %s (%08x)]", &comprType, cType); + } + if (CommChunk.numChannels != 1) { + fail_parse("file contains %d channels, only 1 channel supported", CommChunk.numChannels); + } + if (CommChunk.sampleSize != 16) { + fail_parse("file contains %d bit samples, only 16 bit samples supported", CommChunk.sampleSize); + } + + nSamples = (CommChunk.numFramesH << 16) + CommChunk.numFramesL; + + // Allow broken input lengths + if (nSamples % 16) { + nSamples -= (nSamples % 16); + } + + if (nSamples % 16 != 0) { + fail_parse("number of chunks must be a multiple of 16, found %d with remainder %d", nSamples, nSamples % 16); + } + break; + + case 0x53534e44: // SSND + checked_fread(&SndDChunk, sizeof(SndDChunk), 1, ifile); + BSWAP32(SndDChunk.offset); + BSWAP32(SndDChunk.blockSize); + assert(SndDChunk.offset == 0); + assert(SndDChunk.blockSize == 0); + soundPointer = ftell(ifile); + break; + + case 0x4150504c: // APPL + checked_fread(&ts, sizeof(u32), 1, ifile); + BSWAP32(ts); + if (ts == 0x73746f63) { // stoc + u8 len; + checked_fread(&len, 1, 1, ifile); + if (len == 11) { + char ChunkName[12]; + s16 version; + checked_fread(ChunkName, 11, 1, ifile); + ChunkName[11] = '\0'; + if (strcmp("VADPCMCODES", ChunkName) == 0) { + checked_fread(&version, sizeof(s16), 1, ifile); + BSWAP16(version); + if (version != 1) { + fail_parse("Unknown codebook chunk version"); + } + readaifccodebook(ifile, &coefTable, &order, &npredictors); + } + else if (strcmp("VADPCMLOOPS", ChunkName) == 0) { + checked_fread(&version, sizeof(s16), 1, ifile); + BSWAP16(version); + if (version != 1) { + fail_parse("Unknown loop chunk version"); + } + aloops = readlooppoints(ifile, &nloops); + if (nloops != 1) { + fail_parse("Only a single loop supported"); + } + } + } + } + break; + } + + fseek(ifile, offset + Header.ckSize, SEEK_SET); + } + + if (coefTable == NULL) { + fail_parse("Codebook missing from bitstream"); + } + + for (s32 i = 0; i < order; i++) { + state[15 - i] = 0; + } + + u32 outputBytes = nSamples * sizeof(s16); + u8 *outputBuf = malloc(outputBytes); + + fseek(ifile, soundPointer, SEEK_SET); + s32 fails = 0; + while (currPos < nSamples) { + u8 input[9]; + u8 encoded[9]; + s32 lastState[16]; + s32 decoded[16]; + s16 guess[16]; + s16 origGuess[16]; + + memcpy(lastState, state, sizeof(state)); + checked_fread(input, framesize, 1, ifile); + + // Decode for real + my_decodeframe(input, decompressed, state, order, coefTable); + memcpy(decoded, state, sizeof(state)); + + // Create a guess from that, by clamping to 16 bits + for (s32 i = 0; i < 16; i++) { + origGuess[i] = clamp_bits(state[i], 16); + } + + // Encode the guess + memcpy(guess, origGuess, sizeof(guess)); + my_encodeframe(encoded, guess, lastState, coefTable, order, npredictors); + + // If it doesn't match, bruteforce the matching. + if (memcmp(input, encoded, framesize) != 0) { + s32 guess32[16]; + if (bruteforce(guess32, input, decoded, decompressed, lastState, coefTable, order, npredictors)) { + for (int i = 0; i < 16; i++) { + assert(-0x8000 <= guess32[i] && guess32[i] <= 0x7fff); + guess[i] = guess32[i]; + } + my_encodeframe(encoded, guess, lastState, coefTable, order, npredictors); + assert(memcmp(input, encoded, framesize) == 0); + } else { + fails++; + fprintf(stderr, "FAIL [%d/%d]\n", currPos, nSamples); + } + + // Bring the matching closer to the original decode (not strictly + // necessary, but it will move us closer to the target on average). + for (s32 failures = 0; failures < 50; failures++) { + s32 ind = myrand() % 16; + s32 old = guess[ind]; + if (old == origGuess[ind]) continue; + guess[ind] = origGuess[ind]; + if (myrand() % 2) guess[ind] += (old - origGuess[ind]) / 2; + my_encodeframe(encoded, guess, lastState, coefTable, order, npredictors); + if (memcmp(input, encoded, framesize) == 0) { + failures = -1; + } + else { + guess[ind] = old; + } + } + } + + memcpy(state, decoded, sizeof(state)); + BSWAP16_MANY(guess, 16); + memcpy(outputBuf + currPos * 2, guess, sizeof(guess)); + currPos += 16; + } + if (fails) { + fprintf(stderr, "%s %d\n", infilename, fails); + } + + // Write an incomplete file header. We'll fill in the size later. + fwrite("FORM\0\0\0\0AIFF", 12, 1, ofile); + + // Subtract 4 from the COMM size to skip the compression field. + write_header(ofile, "COMM", sizeof(CommonChunk) - 4); + CommChunk.numFramesH = nSamples >> 16; + CommChunk.numFramesL = nSamples & 0xffff; + BSWAP16(CommChunk.numChannels); + BSWAP16(CommChunk.numFramesH); + BSWAP16(CommChunk.numFramesL); + BSWAP16(CommChunk.sampleSize); + fwrite(&CommChunk, sizeof(CommonChunk) - 4, 1, ofile); + + if (nloops > 0) { + s32 startPos = aloops[0].start, endPos = aloops[0].end; + const char *markerNames[2] = {"start", "end"}; + Marker markers[2] = { + {1, startPos >> 16, startPos & 0xffff}, + {2, endPos >> 16, endPos & 0xffff} + }; + write_header(ofile, "MARK", 2 + 2 * sizeof(Marker) + 1 + 5 + 1 + 3); + s16 numMarkers = bswap16(2); + fwrite(&numMarkers, sizeof(s16), 1, ofile); + for (s32 i = 0; i < 2; i++) { + u8 len = (u8) strlen(markerNames[i]); + BSWAP16(markers[i].MarkerID); + BSWAP16(markers[i].positionH); + BSWAP16(markers[i].positionL); + fwrite(&markers[i], sizeof(Marker), 1, ofile); + fwrite(&len, 1, 1, ofile); + fwrite(markerNames[i], len, 1, ofile); + } + + write_header(ofile, "INST", sizeof(InstrumentChunk)); + InstChunk.sustainLoop.playMode = bswap16(1); + InstChunk.sustainLoop.beginLoop = bswap16(1); + InstChunk.sustainLoop.endLoop = bswap16(2); + InstChunk.releaseLoop.playMode = 0; + InstChunk.releaseLoop.beginLoop = 0; + InstChunk.releaseLoop.endLoop = 0; + fwrite(&InstChunk, sizeof(InstrumentChunk), 1, ofile); + } + + // Save the coefficient table for use when encoding. Ideally this wouldn't + // be needed and "tabledesign -s 1" would generate the right table, but in + // practice it's difficult to adjust samples to make that happen. + write_header(ofile, "APPL", 4 + 12 + sizeof(CodeChunk) + npredictors * order * 8 * 2); + fwrite("stoc", 4, 1, ofile); + CodeChunk cChunk; + cChunk.version = bswap16(1); + cChunk.order = bswap16(order); + cChunk.nEntries = bswap16(npredictors); + fwrite("\x0bVADPCMCODES", 12, 1, ofile); + fwrite(&cChunk, sizeof(CodeChunk), 1, ofile); + for (s32 i = 0; i < npredictors; i++) { + for (s32 j = 0; j < order; j++) { + for (s32 k = 0; k < 8; k++) { + s16 ts = bswap16(coefTable[i][k][j]); + fwrite(&ts, sizeof(s16), 1, ofile); + } + } + } + + write_header(ofile, "SSND", outputBytes + 8); + SndDChunk.offset = 0; + SndDChunk.blockSize = 0; + fwrite(&SndDChunk, sizeof(SoundDataChunk), 1, ofile); + fwrite(outputBuf, outputBytes, 1, ofile); + + // Fix the size in the header + s32 fileSize = bswap32(ftell(ofile) - 8); + fseek(ofile, 4, SEEK_SET); + fwrite(&fileSize, 4, 1, ofile); + + fclose(ifile); + fclose(ofile); + return 0; +} diff --git a/tools/aiff_extract_codebook.c b/tools/aiff_extract_codebook.c new file mode 100644 index 00000000000..78864e3801b --- /dev/null +++ b/tools/aiff_extract_codebook.c @@ -0,0 +1,185 @@ +/** + * Create an ADPCM codebook either by extracting it from an AIFF section, or + * by executing tabledesign. + */ +#define _XOPEN_SOURCE 500 +#include +#include +#include +#include +#include +#include + +typedef short s16; +typedef int s32; +typedef unsigned char u8; +typedef unsigned int u32; + +#define BSWAP16(x) x = __builtin_bswap16(x) +#define BSWAP32(x) x = __builtin_bswap32(x) + +#define NORETURN __attribute__((noreturn)) +#define UNUSED __attribute__((unused)) + +typedef struct +{ + u32 start; + u32 end; + u32 count; + s16 state[16]; +} ALADPCMloop; + +static const char usage[] = "input.aiff"; +static const char *progname, *infilename; + +#define checked_fread(a, b, c, d) if (fread(a, b, c, d) != c) fail_parse("error parsing file") + +NORETURN +void fail_parse(const char *fmt, ...) +{ + char *formatted = NULL; + va_list ap; + va_start(ap, fmt); + int size = vsnprintf(NULL, 0, fmt, ap); + va_end(ap); + if (size >= 0) { + size++; + formatted = malloc(size); + if (formatted != NULL) { + va_start(ap, fmt); + size = vsnprintf(formatted, size, fmt, ap); + va_end(ap); + if (size < 0) { + free(formatted); + formatted = NULL; + } + } + } + + if (formatted != NULL) { + fprintf(stderr, "%s: %s [%s]\n", progname, formatted, infilename); + free(formatted); + } + exit(1); +} + +s32 readaifccodebook(FILE *fhandle, s32 ****table, s16 *order, s16 *npredictors) +{ + checked_fread(order, sizeof(s16), 1, fhandle); + BSWAP16(*order); + checked_fread(npredictors, sizeof(s16), 1, fhandle); + BSWAP16(*npredictors); + *table = malloc(*npredictors * sizeof(s32 **)); + for (s32 i = 0; i < *npredictors; i++) { + (*table)[i] = malloc(8 * sizeof(s32 *)); + for (s32 j = 0; j < 8; j++) { + (*table)[i][j] = malloc((*order + 8) * sizeof(s32)); + } + } + + for (s32 i = 0; i < *npredictors; i++) { + s32 **table_entry = (*table)[i]; + for (s32 j = 0; j < *order; j++) { + for (s32 k = 0; k < 8; k++) { + s16 ts; + checked_fread(&ts, sizeof(s16), 1, fhandle); + BSWAP16(ts); + table_entry[k][j] = ts; + } + } + + for (s32 k = 1; k < 8; k++) { + table_entry[k][*order] = table_entry[k - 1][*order - 1]; + } + + table_entry[0][*order] = 1 << 11; + + for (s32 k = 1; k < 8; k++) { + s32 j = 0; + for (; j < k; j++) { + table_entry[j][k + *order] = 0; + } + + for (; j < 8; j++) { + table_entry[j][k + *order] = table_entry[j - k][*order]; + } + } + } + return 0; +} + +int main(int argc, char **argv) +{ + s16 order = -1; + s16 npredictors = -1; + s32 ***coefTable = NULL; + FILE *ifile; + progname = argv[0]; + + if (argc < 2) { + fprintf(stderr, "%s %s\n", progname, usage); + exit(1); + } + + infilename = argv[1]; + + if ((ifile = fopen(infilename, "rb")) == NULL) { + fail_parse("AIFF file could not be opened"); + exit(1); + } + + char buf[5] = {0}; + checked_fread(buf, 4, 1, ifile); + if (strcmp(buf, "FORM") != 0) fail_parse("not an AIFF file"); + checked_fread(buf, 4, 1, ifile); + checked_fread(buf, 4, 1, ifile); + if (strcmp(buf, "AIFF") != 0 && strcmp(buf, "AIFC") != 0) { + fail_parse("not an AIFF file"); + } + + for (;;) { + s32 size; + if (!fread(buf, 4, 1, ifile) || !fread(&size, 4, 1, ifile)) break; + BSWAP32(size); + s32 nextOffset = ftell(ifile) + ((size + 1) & ~1); + + if (strcmp(buf, "APPL") == 0) { + checked_fread(buf, 4, 1, ifile); + if (strcmp(buf, "stoc") == 0) { + u8 len; + checked_fread(&len, 1, 1, ifile); + if (len == 11) { + char chunkName[12]; + s16 version; + checked_fread(chunkName, 11, 1, ifile); + chunkName[11] = '\0'; + if (strcmp(chunkName, "VADPCMCODES") == 0) { + checked_fread(&version, sizeof(s16), 1, ifile); + BSWAP16(version); + if (version == 1) { + readaifccodebook(ifile, &coefTable, &order, &npredictors); + } + } + } + } + } + + fseek(ifile, nextOffset, SEEK_SET); + } + fclose(ifile); + + if (coefTable == NULL) { + execl("./tools/tabledesign", "tabledesign", "-s", "1", infilename, NULL); + } else { + printf("%d\n%d\n", order, npredictors); + for (s32 i = 0; i < npredictors; i++) { + for (s32 j = 0; j < order; j++) { + for (s32 k = 0; k < 8; k++) { + printf("% 5d ", coefTable[i][k][j]); + } + puts(""); + } + } + } + return 0; +} diff --git a/tools/assemble_font_includes.py b/tools/assemble_font_includes.py new file mode 100644 index 00000000000..6ccd088e230 --- /dev/null +++ b/tools/assemble_font_includes.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python3 +import argparse +import os +from pathlib import Path + +import xml.etree.ElementTree as XmlTree + +from makeelf.elf import * +from audio_common import * + +def get_fonts(font_path): + return [parse_font(font_file) for font_file in os.listdir(font_path) if file.endswith(".xml")] + +def parse_font(font_file): + xml = XmlTree.parse(font_file) + root = xml.getroot() + font = Soundfont() + font.fromXML(root) + font_name = os.path.basename(font_file)[:-4] + if font_name[0:1].isnumeric(): + idx = font_name.find('_') + if idx >= 0: + font.idx = int(font_name[:idx]) + font.name = font_name[idx + 1:] + return font + +def main(args): + fonts = get_fonts(args.xmlpath) + os.makedirs(args.outpath, exist_ok=True) + for font in fonts: + incfile = os.path.join(args.outpath, f"{font.idx}.inc") + if not args.quiet: + print(f"Generating {incfile} from {args.infont}") + write_soundfont_define(font, len(fonts), incfile) + +if __name__ == "__main__": + # Args + parser = argparse.ArgumentParser(add_help=False) + parser.add_argument("xmlpath", type=Path, help="Path to soundfont XMLs.") + parser.add_argument("outpath", type=Path, help="The path to generate the INC files.") + parser.add_argument("--quiet", "-q", action="store_true", help="Suppresses output to standard out.") + parser.add_argument("--help", "-h", "-?", action="help", help="Show this help message and exit.") + args = parser.parse_args() + main(args) diff --git a/tools/assemble_sequence.cpp b/tools/assemble_sequence.cpp new file mode 100644 index 00000000000..c4514dab36d --- /dev/null +++ b/tools/assemble_sequence.cpp @@ -0,0 +1,1364 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "elfio/elfio.hpp" +using namespace std; +using namespace ELFIO; + +bool tryLoadFile(string_view filename, ifstream* outStream); + +// TODO: validate this? probably needs more explicit section annotations in the seq script +enum class SectionType { + Meta, + Seq, + Chan, + Layer, + Unused, + Table, + Array, + Filter, + Envelope, + Buffer +}; + +static const map SectionName { + { SectionType::Meta, "metadata" }, + { SectionType::Seq, "sequence" }, + { SectionType::Chan, "channel" }, + { SectionType::Layer, "layer" }, + { SectionType::Unused, "unused" }, + { SectionType::Table, "table" }, + { SectionType::Array, "array" }, + { SectionType::Filter, "filter" }, + { SectionType::Envelope, "envelope" }, + { SectionType::Buffer, "buffer" }, +}; + +enum class Arg { + var, + varlong, + s8, + u8, + u8OrVar, + s16, + u16, + u16OrAddr, + addr, + reladdr8, + reladdr16, + bits3, + bits4, + bits6, + optu8 +}; + +struct Command { + initializer_list validSections; + uint8_t opcode; + const char* mnemonic; + initializer_list args; +}; + +const Command commands[] = { + { { SectionType::Seq, SectionType::Chan, SectionType::Layer }, 0xFF, "end", {} }, + { { SectionType::Seq, SectionType::Chan }, 0xFE, "delay1", {} }, + { { SectionType::Seq, SectionType::Chan }, 0xFD, "delay", { Arg::var } }, + { { SectionType::Seq, SectionType::Chan, SectionType::Layer }, 0xFC, "call", { Arg::addr } }, + { { SectionType::Seq, SectionType::Chan, SectionType::Layer }, 0xFB, "jump", { Arg::addr } }, + { { SectionType::Seq, SectionType::Chan, SectionType::Layer }, 0xFA, "beqz", { Arg::addr } }, + { { SectionType::Seq, SectionType::Chan, SectionType::Layer }, 0xF9, "bltz", { Arg::addr } }, + { { SectionType::Seq, SectionType::Chan, SectionType::Layer }, 0xF8, "loop", { Arg::u8 } }, + { { SectionType::Seq, SectionType::Chan, SectionType::Layer }, 0xF7, "loopend", {} }, + { { SectionType::Seq, SectionType::Chan, SectionType::Layer }, 0xF6, "break", {} }, + { { SectionType::Seq, SectionType::Chan, SectionType::Layer }, 0xF5, "bgez", { Arg::addr } }, + { { SectionType::Seq, SectionType::Chan, SectionType::Layer }, 0xF4, "rjump", { Arg::reladdr8 } }, + { { SectionType::Seq, SectionType::Chan, SectionType::Layer }, 0xF3, "rbeqz", { Arg::reladdr8 } }, + { { SectionType::Seq, SectionType::Chan, SectionType::Layer }, 0xF2, "rbltz", { Arg::reladdr8 } }, + + { { SectionType::Seq }, 0xF1, "allocnotelist", { Arg::u8 } }, + { { SectionType::Seq }, 0xF0, "freenotelist", {} }, + { { SectionType::Seq }, 0xDF, "transpose", { Arg::s8 } }, + { { SectionType::Seq }, 0xDE, "rtranspose", { Arg::s8 } }, + { { SectionType::Seq }, 0xDD, "tempo", { Arg::u8 } }, + { { SectionType::Seq }, 0xDC, "tempochg", { Arg::s8 } }, + { { SectionType::Seq }, 0xDB, "vol", { Arg::u8 } }, + { { SectionType::Seq }, 0xDA, "volmode", { Arg::s8 } }, + { { SectionType::Seq }, 0xD7, "initchan", { Arg::u16 } }, + { { SectionType::Seq }, 0xD6, "freechan", { Arg::u16 } }, + { { SectionType::Seq }, 0xD5, "mutescale", { Arg::s8 } }, + { { SectionType::Seq }, 0xD4, "mute", {} }, + { { SectionType::Seq }, 0xD3, "mutebhv", { Arg::u8 } }, + { { SectionType::Seq }, 0xD2, "ldshortvelarr", { Arg::addr } }, + { { SectionType::Seq }, 0xD1, "ldshortgatearr", { Arg::addr } }, + { { SectionType::Seq }, 0xD0, "notealloc", { Arg::u8 } }, + { { SectionType::Seq }, 0xCE, "rand", { Arg::u8 } }, + { { SectionType::Seq }, 0xCD, "dyncall", { Arg::addr } }, + { { SectionType::Seq }, 0xCC, "ldi", { Arg::u8 } }, + { { SectionType::Seq }, 0xC9, "and", { Arg::u8 } }, + { { SectionType::Seq }, 0xC8, "sub", { Arg::u8 } }, + { { SectionType::Seq }, 0xC7, "stseq", { Arg::u8, Arg::addr } }, + { { SectionType::Seq }, 0xC6, "stop", {} }, + { { SectionType::Seq }, 0xC5, "scriptctr", { Arg::u16 } }, + { { SectionType::Seq }, 0xC4, "runseq", { Arg::u8, Arg::u8 } }, + + { { SectionType::Seq }, 0x00, "testchan", { Arg::bits4 } }, + { { SectionType::Seq }, 0x40, "stopchan", { Arg::bits4 } }, + { { SectionType::Seq }, 0x50, "subio", { Arg::bits4 } }, + { { SectionType::Seq }, 0x60, "ldres", { Arg::bits4, Arg::u8, Arg::u8 } }, + { { SectionType::Seq }, 0x70, "stio", { Arg::bits4 } }, + { { SectionType::Seq }, 0x80, "ldio", { Arg::bits4 } }, + { { SectionType::Seq }, 0x90, "ldchan", { Arg::bits4, Arg::addr } }, + { { SectionType::Seq }, 0xA0, "rldchan", { Arg::bits4, Arg::reladdr16 } }, + { { SectionType::Seq }, 0xB0, "ldseq", { Arg::bits4, Arg::u8, Arg::addr } }, + + { { SectionType::Chan }, 0xF1, "allocnotelist", { Arg::u8 } }, + { { SectionType::Chan }, 0xF0, "freenotelist", {} }, + { { SectionType::Chan }, 0xEE, "bendfine", { Arg::s8 } }, + { { SectionType::Chan }, 0xED, "gain", { Arg::u8 } }, + { { SectionType::Chan }, 0xEB, "fontinstr", {} }, + { { SectionType::Chan }, 0xEA, "stop", {} }, + { { SectionType::Chan }, 0xE9, "notepri", { Arg::u8 } }, + { { SectionType::Chan }, 0xE8, "params", { Arg::u8, Arg::u8, Arg::u8, Arg::s8, Arg::s8, Arg::u8, Arg::u8, Arg::u8 } }, // TODO: Params for E8 to E6 + { { SectionType::Chan }, 0xE7, "ldparams", { Arg::addr } }, + { { SectionType::Chan }, 0xE6, "samplbook", { Arg::addr } }, + { { SectionType::Chan }, 0xE5, "rvrbidx", { Arg::u8 } }, + { { SectionType::Chan }, 0xE4, "dyncall", {} }, + { { SectionType::Chan }, 0xE3, "vibdelay", { Arg::u8 } }, + { { SectionType::Chan }, 0xE2, "vibdepthgrad", { Arg::u8, Arg::u8, Arg::u8 } }, + { { SectionType::Chan }, 0xE1, "vibfreqgrad", { Arg::u8, Arg::u8, Arg::u8 } }, + { { SectionType::Chan }, 0xE0, "volexp", { Arg::u8 } }, + { { SectionType::Chan }, 0xDF, "vol", { Arg::u8 } }, + { { SectionType::Chan }, 0xDE, "freqscale", { Arg::u16 } }, + { { SectionType::Chan }, 0xDD, "pan", { Arg::u8 } }, + { { SectionType::Chan }, 0xDC, "panweight", { Arg::u8 } }, + { { SectionType::Chan }, 0xDB, "transpose", { Arg::s8 } }, + { { SectionType::Chan }, 0xDA, "env", { Arg::addr } }, + { { SectionType::Chan }, 0xD9, "releaserate", { Arg::u8 } }, + { { SectionType::Chan }, 0xD8, "vibdepth", { Arg::u8 } }, + { { SectionType::Chan }, 0xD7, "vibfreq", { Arg::u8 } }, +// { { SectionType::Chan }, 0xD6, "chan_setupdatesperframe_unimplemented", { Arg::u8 } }, + { { SectionType::Chan }, 0xD4, "reverb", { Arg::u8 } }, + { { SectionType::Chan }, 0xD3, "bend", { Arg::s8 } }, + { { SectionType::Chan }, 0xD2, "sustain", { Arg::u8 } }, + { { SectionType::Chan }, 0xD1, "notealloc", { Arg::u8 } }, + { { SectionType::Chan }, 0xD0, "effects", { Arg::u8 } }, + { { SectionType::Chan }, 0xCF, "stptrtoseq", { Arg::addr } }, + { { SectionType::Chan }, 0xCE, "ldptr", { Arg::u16OrAddr } }, + { { SectionType::Chan }, 0xCD, "stopchan", { Arg::u8 } }, + { { SectionType::Chan }, 0xCC, "ldi", { Arg::u8 } }, + { { SectionType::Chan }, 0xCB, "ldseq", { Arg::addr } }, + { { SectionType::Chan }, 0xCA, "mutebhv", { Arg::u8 } }, + { { SectionType::Chan }, 0xC9, "and", { Arg::u8 } }, + { { SectionType::Chan }, 0xC8, "sub", { Arg::u8 } }, + { { SectionType::Chan }, 0xC7, "stseq", { Arg::u8, Arg::addr } }, + { { SectionType::Chan }, 0xC6, "font", { Arg::u8 } }, + { { SectionType::Chan }, 0xC5, "dyntbllookup", {} }, + { { SectionType::Chan }, 0xC4, "noshort", {} }, + { { SectionType::Chan }, 0xC3, "short", {} }, + { { SectionType::Chan }, 0xC2, "dyntbl", { Arg::addr } }, + { { SectionType::Chan }, 0xC1, "instr", { Arg::u8 } }, + { { SectionType::Chan }, 0xBD, "randptr", { Arg::u16, Arg::u16 } }, + { { SectionType::Chan }, 0xBC, "ptradd", { Arg::u16OrAddr } }, + { { SectionType::Chan }, 0xBB, "unkbb", { Arg::u8, Arg::u16 } }, + { { SectionType::Chan }, 0xBA, "randgate", { Arg::u8 } }, + { { SectionType::Chan }, 0xB9, "randvel", { Arg::u8 } }, + { { SectionType::Chan }, 0xB8, "rand", { Arg::u8 } }, + { { SectionType::Chan }, 0xB7, "randtoptr", { Arg::u16OrAddr } }, + { { SectionType::Chan }, 0xB6, "dyntblv", {} }, + { { SectionType::Chan }, 0xB5, "dyntbltoptr", {} }, + { { SectionType::Chan }, 0xB4, "ptrtodyntbl", {} }, + { { SectionType::Chan }, 0xB3, "filter", { Arg::u8 } }, + { { SectionType::Chan }, 0xB2, "ldseqtoptr", { Arg::addr } }, + { { SectionType::Chan }, 0xB1, "freefilter", {} }, + { { SectionType::Chan }, 0xB0, "ldfilter", { Arg::addr } }, + + { { SectionType::Chan }, 0x00, "cdelay", { Arg::bits4 } }, + { { SectionType::Chan }, 0x10, "sample", { Arg::bits3, Arg::addr } }, + { { SectionType::Chan }, 0x18, "sampleptr", { Arg::bits3, Arg::addr } }, + { { SectionType::Chan }, 0x20, "ldchan", { Arg::bits4, Arg::addr } }, + { { SectionType::Chan }, 0x30, "stcio", { Arg::bits4, Arg::u8 } }, + { { SectionType::Chan }, 0x40, "ldcio", { Arg::bits4, Arg::u8 } }, + { { SectionType::Chan }, 0x50, "subio", { Arg::bits4 } }, + { { SectionType::Chan }, 0x60, "ldio", { Arg::bits4 } }, + { { SectionType::Chan }, 0x70, "stio", { Arg::bits3 } }, + { { SectionType::Chan }, 0x78, "rldlayer", { Arg::bits3, Arg::reladdr16 } }, + { { SectionType::Chan }, 0x80, "testlayer", { Arg::bits3 } }, + { { SectionType::Chan }, 0x88, "ldlayer", { Arg::bits3, Arg::addr } }, + { { SectionType::Chan }, 0x90, "dellayer", { Arg::bits3 } }, + { { SectionType::Chan }, 0x98, "dynldlayer", { Arg::bits3 } }, + + { { SectionType::Layer }, 0xC0, "ldelay", { Arg::var } }, + { { SectionType::Layer }, 0xC0, "lldelay", { Arg::varlong } }, // Workaround for weirdly encoded numbers + { { SectionType::Layer }, 0xC1, "shortvel", { Arg::u8 } }, + { { SectionType::Layer }, 0xC2, "transpose", { Arg::s8 } }, + { { SectionType::Layer }, 0xC3, "shortdelay", { Arg::var } }, + { { SectionType::Layer }, 0xC4, "legato", {} }, + { { SectionType::Layer }, 0xC5, "nolegato", {} }, + { { SectionType::Layer }, 0xC6, "instr", { Arg::u8 } }, + { { SectionType::Layer }, 0xC7, "portamento", { Arg::u8, Arg::u8, Arg::u8OrVar } }, + { { SectionType::Layer }, 0xC7, "portamentofix", { Arg::u8, Arg::u8, Arg::u8 } }, + { { SectionType::Layer }, 0xC8, "noportamento", {} }, + { { SectionType::Layer }, 0xC9, "shortgate", { Arg::u8 } }, + { { SectionType::Layer }, 0xCA, "notepan", { Arg::u8 } }, + { { SectionType::Layer }, 0xCB, "env", { Arg::addr, Arg::u8 } }, + { { SectionType::Layer }, 0xCC, "nodrumpan", {} }, + { { SectionType::Layer }, 0xCD, "stereo", { Arg::u8 } }, + { { SectionType::Layer }, 0xCE, "bendfine", { Arg::s8 } }, + { { SectionType::Layer }, 0xCF, "releaserate", { Arg::u8 } }, + + { { SectionType::Layer }, 0xD0, "ldshortvel", { Arg::bits4 } }, + { { SectionType::Layer }, 0xE0, "ldshortgate", { Arg::bits4 } }, + + { { SectionType::Layer }, 0x00, "notedvg", { Arg::bits6, Arg::var, Arg::u8, Arg::u8 } }, + { { SectionType::Layer }, 0x40, "notedv", { Arg::bits6, Arg::var, Arg::u8 } }, + { { SectionType::Layer }, 0x40, "noteldv", { Arg::bits6, Arg::varlong, Arg::u8 } }, // Workaround for weirdly encoded numbers + { { SectionType::Layer }, 0x80, "notevg", { Arg::bits6, Arg::u8, Arg::u8 } }, + + { { SectionType::Layer }, 0x00, "shortdvg", { Arg::bits6, Arg::var } }, + { { SectionType::Layer }, 0x40, "shortdv", { Arg::bits6 } }, + { { SectionType::Layer }, 0x80, "shortvg", { Arg::bits6 } }, + + { { SectionType::Unused }, 0x80, "byte", { Arg::u8, Arg::optu8, Arg::optu8, Arg::optu8, Arg::optu8, Arg::optu8, Arg::optu8, Arg::optu8, + Arg::optu8, Arg::optu8, Arg::optu8, Arg::optu8, Arg::optu8, Arg::optu8, Arg::optu8, Arg::optu8 } }, + { { SectionType::Table }, 0x80, "entry", { Arg::addr } }, + { { SectionType::Filter }, 0x80, "filter", { Arg::s16, Arg::s16, Arg::s16, Arg::s16, Arg::s16, Arg::s16, Arg::s16, Arg::s16 } }, + { { SectionType::Array }, 0x80, "byte", { Arg::u8, Arg::optu8, Arg::optu8, Arg::optu8, Arg::optu8, Arg::optu8, Arg::optu8, Arg::optu8, + Arg::optu8, Arg::optu8, Arg::optu8, Arg::optu8, Arg::optu8, Arg::optu8, Arg::optu8, Arg::optu8 } }, + { { SectionType::Envelope }, 0x80, "point", { Arg::s16, Arg::s16 } }, + { { SectionType::Envelope }, 0x81, "disable", {} }, + { { SectionType::Envelope }, 0x82, "hang", {} }, + { { SectionType::Envelope }, 0x83, "goto", { Arg::u16 } }, + { { SectionType::Envelope }, 0x84, "restart", {} }, + { { SectionType::Buffer }, 0x80, "space", { Arg::u16 } } +}; + +struct ProcessingState { + string_view filename; + string_view line; + uint32_t lineNumber; + SectionType section; + + auto tie() const { return std::tie(filename, line, lineNumber, section); } +}; + +inline bool operator==(const ProcessingState& lhs, const ProcessingState& rhs) { + return lhs.tie() == rhs.tie(); +} + +inline bool operator!=(const ProcessingState& lhs, const ProcessingState& rhs) { + return lhs.tie() != rhs.tie(); +} + +enum class ErrorLevel { + Info, + Warn, + Error +}; + +struct ParseError { + int32_t pos = -1; + ErrorLevel level = ErrorLevel::Error; + string message; + + ParseError(const string& message) : message(message) {} + ParseError(const int32_t pos, const string& message) : pos(pos), message(message) {} + ParseError(const ErrorLevel level, const string& message) : level(level), message(message) {} + + void output(vector fileStack) const; +}; + +void ParseError::output(vector fileStack) const { + for (auto state : fileStack) { + cerr << "in " << state->filename << "@" << state->lineNumber; + if (state != fileStack.back()) { + cerr << endl; + } + } + if (pos >= 0) { + cerr << ":" << pos; + } + cerr << ": "; + switch (level) { + case ErrorLevel::Info: + cerr << "message"; + break; + case ErrorLevel::Warn: + cerr << "parse warning"; + break; + case ErrorLevel::Error: + cerr << "parse error"; + break; + } + cerr << ": " << message << endl; + cerr << fileStack.back()->line << endl; + if (pos >= 0) + cerr << string(pos, '-') << "^" << endl; +} + +bool isValidSymbolChar(char c) { + return isalnum(c) || c == '_'; +} + +bool isValidSymbolStartChar(char c) { + return isalpha(c) || c == '_'; +} + +bool isValidLabelChar(char c) { + return isValidSymbolChar(c); +} + +typedef map> DefineMap; + +class Tokenizer { +public: + Tokenizer(string_view filename, int32_t line, string_view str) { + this->filename = filename; + this->lineNumber = line; + this->str = str; + } + void assertEof(); + bool isEof(); + bool isLabelCharNext(); + string_view readWsSepToken(); + bool readStringLiteral(string* out); + int32_t readInt(const DefineMap& defines) { return parseSum(defines); } + int32_t readInt(const DefineMap& defines, string* symbolOut) { return parseAtom(defines, symbolOut); } + pair readLabelWithOffset(const DefineMap& defines); + bool consumeCommaOrEof(); + bool peekNonWs(char* out); + void consumeRest(); + +private: + string_view filename; + int32_t lineNumber; + string_view str; + size_t ind = 0; + + bool peekRaw(char* out); + bool peek(char* out); + + void consume(); + void consumeWs(); + template + string_view consumeWhile(const F& pred); + + int32_t toI32(int64_t n); + int32_t parseSum(const DefineMap& defines); + int32_t parseProd(const DefineMap& defines); + int32_t parseAtom(const DefineMap& defines); + int32_t parseAtom(const DefineMap& defines, string* symbolOut); + int32_t parseNumber(char firstChar); +}; + +bool Tokenizer::peekRaw(char* out) { + if (ind == str.size()) return false; + *out = str[ind]; + return true; +} + +bool Tokenizer::peek(char* out) { + return peekRaw(out) && *out != '#'; +} + +bool Tokenizer::peekNonWs(char* out) { + while (peek(out)) { + if (isspace(*out)) consume(); + else return true; + } + return false; +} + +void Tokenizer::assertEof() { + consumeWs(); + char c; + if (peek(&c)) { + throw ParseError(ind, "extraneous data: " + string(1, c)); + } +} + +bool Tokenizer::isEof() { + consumeWs(); + char c; + return !peek(&c); +} + +bool Tokenizer::isLabelCharNext() { + char c; + peekNonWs(&c); + return isValidSymbolStartChar(c); +} + +void Tokenizer::consume() { + assert(ind != str.size()); + ind++; +} + +void Tokenizer::consumeWs() { + char c; + peekNonWs(&c); +} + +void Tokenizer::consumeRest() { + ind = str.size(); +} + +bool Tokenizer::consumeCommaOrEof() { + char c; + if (!peekNonWs(&c)) + return false; + if (c != ',') + throw ParseError(ind, "invalid syntax, comma expected"); + consume(); + return true; +} + +template +string_view Tokenizer::consumeWhile(const F& pred) { + size_t start = ind; + char c; + while (peek(&c) && pred(c)) + consume(); + return str.substr(start, ind - start); +} + +string_view Tokenizer::readWsSepToken() { + consumeWs(); + return consumeWhile([](char c) { + return !isspace(c); + }); +} + +bool Tokenizer::readStringLiteral(string* out) { + consumeWs(); + char c; + if (!peek(&c) || c != '"') return false; + consume(); + out->clear(); + for (;;) { + if (!peekRaw(&c)) + throw ParseError(ind, "unterminated string literal"); + consume(); + if (c == '"') break; + if (c == '\\') { + if (!peekRaw(&c)) + throw ParseError(ind, "trailing backslash"); + consume(); + if (c == 'n') c = '\n'; + else if (c == 'r') c = '\r'; + else if (c == 't') c = '\t'; + else if (c == '0') c = '\0'; + } + *out += c; + } + return true; +} + +int32_t Tokenizer::toI32(int64_t n) { + if (-0x7FFFFFFF-1 <= n && n <= 0x7FFFFFFF) + return (int32_t)n; + throw ParseError(ind, "arithmetic out of range"); +} + +int32_t Tokenizer::parseSum(const DefineMap& defines) { + int32_t a = parseProd(defines); + char c; + while (peekNonWs(&c) && (c == '+' || c == '-')) { + consume(); + int64_t b = parseProd(defines); + a = toI32(a + b * (c == '+' ? 1 : -1)); + } + return a; +} + +int32_t Tokenizer::parseProd(const DefineMap& defines) { + int32_t a = parseAtom(defines); + char c; + while (peekNonWs(&c) && c == '*') { + consume(); + int64_t b = parseAtom(defines); + a = toI32(a * b); + } + return a; +} + +int32_t Tokenizer::parseAtom(const DefineMap& defines) { + string dumpBuffer; + return parseAtom(defines, &dumpBuffer); +} + +int32_t Tokenizer::parseAtom(const DefineMap& defines, string* symbolOut) { + char c; + if (!peekNonWs(&c)) + throw ParseError(ind, "bad math expression: empty terminal"); + if (c == '-') { + consume(); + return toI32(-(int64_t)parseAtom(defines)); + } + if (c == '(') { + consume(); + int32_t a = parseSum(defines); + if (!peekNonWs(&c) || c != ')') + throw ParseError(ind, "bad math expression: expected )"); + consume(); + return a; + } + if ('0' <= c && c <= '9') { + consume(); + return parseNumber(c); + } + + string_view s = consumeWhile(isValidSymbolChar); + if (s.empty()) + throw ParseError(ind, "bad math expression: unable to parse " + string(1, c)); + + auto it = defines.find(s); + if (it != defines.end()) { + symbolOut->clear(); + for (char c : it->first) + *symbolOut += c; + return it->second; + } + + throw ParseError(ind, "bad math expression: symbol " + string(s) + " not found"); +} + +int32_t Tokenizer::parseNumber(char firstChar) { + int32_t radix = 10; + char c; + if (firstChar == '0') { + if (!peekRaw(&c)) return 0; + if (c == 'x' || c == 'X') { + radix = 16; + } else if (c == 'b' || c == 'B') { + radix = 2; + } else if ('0' <= c && c <= '9') { + throw ParseError(ind, "octal literals are not supported"); + } else { + return 0; + } + consume(); + } + + int32_t ret = firstChar - '0'; + bool needOne = (radix != 10); + while (peekRaw(&c)) { + int32_t digit; + if ('0' <= c && c <= '9') { + digit = c - '0'; + } else if ('a' <= c && c <= 'z') { + digit = c - 'a' + 10; + } else if ('A' <= c && c <= 'Z') { + digit = c - 'A' + 10; + } else { + break; + } + if (digit >= radix) + throw ParseError(ind, "invalid number"); + consume(); + ret = toI32((int64_t)ret * radix + digit); + needOne = false; + } + if (needOne) + throw ParseError(ind, "invalid number"); + return ret; +} + +pair Tokenizer::readLabelWithOffset(const DefineMap& defines) { + consumeWs(); + string_view s = consumeWhile([](char c) { return isValidLabelChar(c) || c == '@'; }); + if (s.empty()) + throw ParseError(ind, "label expected"); + if (s.compare("@") != 0 && !isValidSymbolStartChar(s[0])) + throw ParseError(ind - s.size(), "label must start with letter or underscore"); + int32_t a = 0; + char c; + while (peekNonWs(&c) && (c == '+' || c == '-')) { + consume(); + int64_t b = parseProd(defines); + a = toI32(a + b * (c == '+' ? 1 : -1)); + } + return {s, a}; +} + +struct LabelDescriptor { + SectionType section; + int64_t offset; +}; + +class Compiler { +public: + Compiler(string_view fontpath); + void processFile(istream& is, string_view filename); + void applyFixups(); + void write(ostream& os); + vector getFontIds(); + map> getLabels(); + uint8_t getCachePolicy(); + +private: + struct Fixup { + size_t pos; + string label; + int32_t offset; + Arg arg; + int64_t relativeTo; + int lineNumber; + }; + + string_view fontpath; + uint8_t cachePolicy = 2; + vector output; + vector fixups; + static const map labelMetaCommands; + static const unordered_set globalMetaCommands; + static const map sectionAlignment; + map> labelValues; + map> commandMap; + DefineMap definedSymbols; + vector fileStack; + vector fontIds; + SectionType currentSection() { return fileStack.back()->section; } + void changeCurrentSection(SectionType section) { fileStack.back()->section = section; } + void info(string message) { auto p = ParseError(ErrorLevel::Info, message); p.output(fileStack); } + void warn(string message) { auto p = ParseError(ErrorLevel::Warn, message); p.output(fileStack); } + void assertMetaMode(); + void assertNormalMode(); + void processUseFont(Tokenizer& tk); + void processLine(string_view line, string_view filename, int lineNumber); + void processLabelMetaCommand(string_view cmd, Tokenizer& tk, bool noAlign); + void processGlobalMetaCommand(string_view cmd, Tokenizer& tk, string_view filename); + void processMetaCommand(string_view cmd, Tokenizer& tk); + void processDataCommand(string_view mnemonic, Tokenizer& tk, int lineNumber); + void processTrackCommand(string_view mnemonic, Tokenizer& tk, int lineNumber); + void emitCommandArgument(Arg a, Tokenizer& tk, int32_t* valOut); + void write(int16_t v); + void balign(int32_t to); +}; + +const map Compiler::labelMetaCommands = { + { ".sequence", SectionType::Seq }, + { ".channel", SectionType::Chan }, + { ".layer", SectionType::Layer }, + { ".unused", SectionType::Unused }, + { ".table", SectionType::Table }, + { ".array", SectionType::Array }, + { ".filter", SectionType::Filter }, + { ".envelope", SectionType::Envelope }, + { ".buffer", SectionType::Buffer } +}; + +const map Compiler::sectionAlignment { +// { SectionType::Table, 2 }, + { SectionType::Envelope, 2 }, + { SectionType::Buffer, 16 }, + { SectionType::Filter, 16 } +}; + +const unordered_set Compiler::globalMetaCommands { + ".define", + ".include" +}; + +Compiler::Compiler(string_view fontpath) : fontpath(fontpath) { + for (const Command& cmd : commands) { + for (const SectionType section : cmd.validSections) { + assert(!commandMap[section].count(cmd.mnemonic)); + commandMap[section][cmd.mnemonic] = cmd; + } + } +} + +void Compiler::processFile(istream& in, string_view filename) { + string line; + int lineNumber = 0; + ProcessingState fileState; + + fileState.filename = filename; + fileState.section = SectionType::Meta; + fileState.lineNumber = lineNumber; + fileStack.emplace_back(&fileState); + + while (getline(in, line)) { + lineNumber++; + try { + processLine(line, filename, lineNumber); + } catch (const ParseError& e) { + e.output(fileStack); + + exit(1); + } + } + + fileStack.pop_back(); +} + +void Compiler::applyFixups() { + for (const Fixup& f : fixups) { + int64_t target; + if (f.label == "@") { + target = f.relativeTo; + } else { + auto it = labelValues.find(f.label); + if (it == labelValues.end()) { + cerr << "Error: on line " << f.lineNumber + << ": reference to undefined label " << f.label << endl; + exit(1); + } + target = it->second.offset; + } + target += f.offset; + + int32_t minTarget, maxTarget; + + switch (f.arg) { + case Arg::reladdr8: + target -= f.relativeTo; + minTarget = -0x80; + maxTarget = 0x7F; + output[f.pos] = (uint8_t)(target & 0xFF); + break; + case Arg::reladdr16: + target -= f.relativeTo; + minTarget = -0x8000; + maxTarget = 0x7FFF; + output[f.pos] = (uint8_t)((target & 0xFF00) >> 8); + output[f.pos + 1] = (uint8_t)(target & 0xFF); + break; + case Arg::addr: + case Arg::u16OrAddr: + minTarget = 0; + maxTarget = 0xFFFF; + output[f.pos] = (uint8_t)((target & 0xFF00) >> 8); + output[f.pos + 1] = (uint8_t)(target & 0xFF); + break; + default: + assert(!"bad fixup arg type"); + } + + if (target < minTarget || target >= maxTarget) { + cerr << "Error: on line " << f.lineNumber + << ": reference to " << f.label << " which is too far away" << endl; + exit(1); + } + } +} + +vector Compiler::getFontIds() { + return fontIds; +} + +uint8_t Compiler::getCachePolicy() { + return cachePolicy; +} + +map> Compiler::getLabels() { + return labelValues; +} + +void Compiler::write(ostream& os) { + os.write((const char*)output.data(), output.size()); +} + +void Compiler::assertNormalMode() { + if (currentSection() == SectionType::Meta) { + throw ParseError("command cannot be used in metadata section"); + } +} + +void Compiler::assertMetaMode() { + if (currentSection() != SectionType::Meta) { + throw ParseError("command can only be used in metadata section"); + } +} + +void Compiler::processLine(string_view line, string_view filename, int lineNumber) { + static bool overrideAlignment = false; + auto currentState = fileStack.back(); + currentState->line = line; + currentState->lineNumber = lineNumber; + + Tokenizer tk(filename, lineNumber, line); + + string_view cmd = tk.readWsSepToken(); + + if (cmd.empty()) return; + + if (labelMetaCommands.count(cmd)) { + processLabelMetaCommand(cmd, tk, overrideAlignment); + return; + } + + if (globalMetaCommands.count(cmd)) { + processGlobalMetaCommand(cmd, tk, filename); + return; + } + + // This needs to be done after processing label metacommands. + if (overrideAlignment) + overrideAlignment = false; + + if (cmd.compare(".balign") == 0) { + int32_t width = tk.readInt(definedSymbols); + balign(width); + overrideAlignment = true; + return; + } + + switch (currentSection()) { + case SectionType::Meta: + processMetaCommand(cmd, tk); + break; + case SectionType::Seq: + case SectionType::Chan: + case SectionType::Layer: + processTrackCommand(cmd, tk, lineNumber); + break; + case SectionType::Array: + case SectionType::Table: + case SectionType::Buffer: + case SectionType::Filter: + case SectionType::Envelope: + case SectionType::Unused: + processDataCommand(cmd, tk, lineNumber); + break; + } + + tk.assertEof(); +} + +void Compiler::processGlobalMetaCommand(string_view cmd, Tokenizer& tk, string_view filename) { + if (cmd == ".include") { + string dir = filesystem::path(filename).parent_path(); + string includedFilename; + if (!tk.readStringLiteral(&includedFilename)) + throw ParseError("expected string literal"); + if (dir[dir.size() - 1] != '/') + dir += '/'; + includedFilename = dir + includedFilename; + ifstream fin(includedFilename); + if (!fin) { + throw ParseError("failed to open " + includedFilename); + } + processFile(fin, includedFilename); + } else if (cmd == ".define") { + string sym(tk.readWsSepToken()); + if (sym.empty()) + throw ParseError(".define without argument"); + for (char c : sym) { + if (!isValidSymbolChar(c)) + throw ParseError("invalid define name " + sym); + } + if ('0' <= sym[0] && sym[0] <= '9') + throw ParseError("invalid define name " + sym + " (cannot start with a digit)"); + definedSymbols[sym] = tk.readInt(definedSymbols); + } +} + +void Compiler::processLabelMetaCommand(string_view cmd, Tokenizer& tk, bool noAlign) { + auto requestedSection = labelMetaCommands.at(cmd); + auto labelName = tk.readWsSepToken(); + + if (labelName.empty()) + throw ParseError("empty label not allowed"); + for (char c : labelName) { + if (!isValidLabelChar(c)) + throw ParseError("invalid label name"); + } + if (labelValues.count(labelName)) + throw ParseError("label " + string(labelName) + " defined twice"); + + if (currentSection() == SectionType::Meta && fileStack.size() < 2) { + if (requestedSection != SectionType::Seq) { + throw ParseError("sequence section must be defined first"); + } + } + + changeCurrentSection(requestedSection); + + if (sectionAlignment.count(currentSection()) && !noAlign) { + balign(sectionAlignment.at(currentSection())); + } + + LabelDescriptor desc; + desc.offset = (int64_t)output.size(); + desc.section = requestedSection; + + labelValues[string(labelName)] = desc; +} + +void Compiler::processMetaCommand(string_view cmd, Tokenizer& tk) { + if (cmd == ".desc") { + // Descriptors are ignored by the assembler. We'll read in the string and then skip the remainder + // of the line. + string meta; + assertMetaMode(); + tk.readWsSepToken(); + tk.readStringLiteral(&meta); + } else if (cmd == ".usefont") { + assertMetaMode(); + processUseFont(tk); + } else if (cmd == ".cache") { + assertMetaMode(); + cachePolicy = tk.readInt(definedSymbols); + } else { + throw ParseError("unrecognized command: " + string(cmd)); + } +} + +void Compiler::processUseFont(Tokenizer& tk) { + string symbol; + int32_t fontid = tk.readInt(definedSymbols, &symbol); + fontIds.emplace_back(fontid); + + // Font symbols are only loaded if fontpath is set. + if (!fontpath.empty()) { + string path = string(fontpath) + "/" + std::to_string(fontid) + ".inc"; + if (filesystem::is_regular_file(path)) { + ifstream fin; + istream* in = &fin; + bool loaded = tryLoadFile(path, &fin); + if (loaded) { + processFile(*in, path); + fin.close(); + return; + } + } + + if (!symbol.empty()) { + path = string(fontpath) + "/" + symbol + ".inc"; + if (filesystem::is_regular_file(path)) { + ifstream fin; + istream* in = &fin; + bool loaded = tryLoadFile(path, &fin); + if (loaded) { + processFile(*in, path); + fin.close(); + return; + } + } + } + + throw ParseError("Could not find soundfont include file for " + (symbol.empty() ? std::to_string(fontid) : symbol)); + } +} + +void Compiler::processDataCommand(string_view mnemonic, Tokenizer& tk, int32_t lineNumber) { + auto cmd = commandMap[currentSection()][mnemonic]; + + if (cmd.mnemonic == NULL) { + throw ParseError("command " + string(mnemonic) + " is invalid for section " + SectionName.at(currentSection())); + } + + // Certain commands output additional bytes beyond just the arguments. We'll handle those cases here first. + if (mnemonic.compare("space") == 0) { + auto amount = tk.readInt(definedSymbols); + if (amount < 0) { + throw ParseError("space cannot be negative"); + } + for (auto i = 0; i < amount; i++) { + output.push_back(0); + } + return; + } + + if (currentSection() == SectionType::Envelope && mnemonic.compare("point") != 0) { + if (mnemonic.compare("disable") == 0) { + write(0); + write(0); + } else if (mnemonic.compare("hang") == 0) { + write(-1); + write(0); + } else if (mnemonic.compare("goto") == 0) { + write(-2); + } else if (mnemonic.compare("restart") == 0) { + write(-3); + write(0); + } + } + + bool firstArg = true; + size_t fixupsInd = fixups.size(); + + for (Arg a : cmd.args) { + if (!firstArg && !tk.consumeCommaOrEof() && a != Arg::optu8) { + throw ParseError("too few arguments"); + } + if (a == Arg::optu8) { + if (tk.isEof()) { + break; + } + a = Arg::u8; + } + emitCommandArgument(a, tk, nullptr); + firstArg = false; + } + while (fixupsInd < fixups.size()) { + Fixup& f = fixups[fixupsInd++]; + f.relativeTo = (int64_t)output.size(); + f.lineNumber = lineNumber; + } +} + +void Compiler::processTrackCommand(string_view mnemonic, Tokenizer& tk, int lineNumber) { + auto cmd = commandMap[currentSection()][mnemonic]; + if (cmd.mnemonic == NULL) { + throw ParseError("command " + string(mnemonic) + " is invalid for section " + SectionName.at(currentSection())); + } + size_t firstInd = output.size(); + output.push_back(cmd.opcode); + bool first = true, needLoBits = false; + int32_t firstVal = 0; + size_t fixupsInd = fixups.size(); + for (Arg a : cmd.args) { + if (!first) { + if (!tk.consumeCommaOrEof() && a != Arg::optu8) + throw ParseError("too few arguments"); + } + if (a == Arg::u8OrVar) + a = firstVal & 0x80 ? Arg::u8 : Arg::var; + if (a == Arg::bits3 || a == Arg::bits4 || a == Arg::bits6) + needLoBits = true; + if (a == Arg::optu8) { + if (tk.isEof()) { + break; + } + a = Arg::u8; + } + emitCommandArgument(a, tk, first ? &firstVal : nullptr); + first = false; + } + char c; + if (tk.peekNonWs(&c) && c == ',') + throw ParseError("too many arguments"); + if (needLoBits) + output[firstInd] = (uint8_t)(output[firstInd] | firstVal); + while (fixupsInd < fixups.size()) { + Fixup& f = fixups[fixupsInd++]; + f.relativeTo = (int64_t)output.size(); + f.lineNumber = lineNumber; + } +} + +void Compiler::emitCommandArgument(Arg a, Tokenizer& tk, int32_t* valOut) { + if (a == Arg::addr || a == Arg::reladdr8 || a == Arg::reladdr16 || (a == Arg::u16OrAddr && tk.isLabelCharNext())) { + string_view label; + int32_t offset; + tie(label, offset) = tk.readLabelWithOffset(definedSymbols); + fixups.push_back({ + output.size(), string(label), offset, a, 0, 0 + }); + output.push_back(0); + if (a == Arg::addr || a == Arg::reladdr16 || a == Arg::u16OrAddr) + output.push_back(0); + return; + } + int32_t v = tk.readInt(definedSymbols); + int32_t minTarget; + int32_t maxTarget; + switch (a) { + case Arg::s8: + minTarget = -128; + maxTarget = 127; + break; + case Arg::u8: + minTarget = 0; + maxTarget = 255; + break; + case Arg::s16: + minTarget = -32768; + maxTarget = 32767; + break; + case Arg::u16: + case Arg::u16OrAddr: + minTarget = 0; + maxTarget = 65535; + break; + case Arg::var: + case Arg::varlong: + minTarget = 0; + maxTarget = 32767; + break; + case Arg::bits3: + minTarget = 0; + maxTarget = 7; + break; + case Arg::bits4: + minTarget = 0; + maxTarget = 15; + break; + case Arg::bits6: + minTarget = 0; + maxTarget = 63; + break; + default: + throw ParseError("invalid argument type " + std::to_string(static_cast(a))); + } + + if (v < minTarget) { + warn("value out of range (" + std::to_string(v) + " < " + std::to_string(minTarget) + "), truncating"); + } + if (v > maxTarget) { + warn("value out of range (" + std::to_string(v) + " > " + std::to_string(maxTarget) + "), truncating"); + } + + if (a == Arg::s8 || a == Arg::u8) { + v &= 0xFF; + output.push_back((uint8_t)v); + } else if (a == Arg::s16 || a == Arg::u16 || a == Arg::u16OrAddr) { + v &= 0xFFFF; + output.push_back((uint8_t)(v >> 8)); + output.push_back((uint8_t)(v & 0xFF)); + } else if (a == Arg::var) { + v &= 0x7FFF; + if (v < 0x80) { + output.push_back((uint8_t)v); + } else { + output.push_back((uint8_t)(v >> 8 | 0x80)); + output.push_back((uint8_t)(v & 0xFF)); + } + } else if (a == Arg::varlong) { + v &= 0x7FFF; + output.push_back((uint8_t)(v >> 8 | 0x80)); + output.push_back((uint8_t)(v & 0xFF)); + } else if (a == Arg::bits3 || a == Arg::bits4 || a == Arg::bits6) { + int32_t mask = (a == Arg::bits3 ? 7 : a == Arg::bits4 ? 15 : 63); + v &= mask; + assert(valOut); + } + if (valOut) + *valOut = v; +} + +void Compiler::write(int16_t v) { + output.push_back((uint8_t)((v & 0xFF00) >> 8)); + output.push_back((uint8_t)(v & 0xFF)); +} + +void Compiler::balign(int32_t to) { + if (to <= 0) throw ParseError(".balign argument must be positive"); + if (to & (to - 1)) throw ParseError(".balign argument must be a power of two"); + while (output.size() & (to - 1)) { + output.push_back(0); + } +} + +int getMachine(string_view machineName, uint8_t width) { + if (machineName.compare("mips") == 0) { + return EM_MIPS; + } + if (machineName.compare("x86") == 0) { + return width == 32 ? EM_486 : EM_X86_64; + } + if (width == 64 && (machineName.compare("x86_64") == 0 || machineName.compare("x86-64") == 0)) { + return EM_X86_64; + } + if (machineName.compare("arm") == 0) { + return width == 32 ? EM_ARM : EM_AARCH64; + } + if (machineName.compare("aarch64") == 0 && width == 64) { + return EM_AARCH64; + } + + cerr << "Machine " << machineName << " and width " << width << " not supported" << endl; + exit(1); +} + +bool tryLoadFile(string_view filename, ifstream* outStream) { + outStream->open(string(filename)); + + return !outStream->fail(); +} + +int main(int argc, char** argv) { + struct ElfOptions { + bool littleEndian; + uint8_t width; + string machine; + }; + + bool printHelp = false; + bool printFonts = false; + bool printLabels = false; + ElfOptions elf; + char optParams = '\0'; + string fontpath; + string cwd = filesystem::current_path(); + vector positionalArgs; + for (int i = 1; i < argc; i++) { + string arg = argv[i]; + if (optParams == 'f') { + fontpath = arg; + optParams = '\0'; + continue; + } + + if (optParams == 'e') { + transform(arg.begin(), arg.end(), arg.begin(), [](uint8_t c) { return tolower(c); }); + if (arg.compare("little") == 0) { + elf.littleEndian = true; + } else if (arg.compare("big") == 0) { + elf.littleEndian = false; + } else { + cerr << "Only big or little accepted, " << arg << " is not recognized" << endl; + exit(1); + } + optParams = 'w'; + continue; + } + + if (optParams == 'w') { + uint8_t width = std::stoi(arg); + if (width != 32 && width != 64) { + cerr << "Bit width must be 32 or 64" << endl; + exit(1); + } + elf.width = width; + optParams = 'm'; + continue; + } + + if (optParams == 'm') { + transform(arg.begin(), arg.end(), arg.begin(), [](uint8_t c) { return tolower(c); }); + elf.machine = arg; + optParams = '\0'; + continue; + } + + if (optParams != '\0') { + cerr << "Missing required parameter" << endl; + printHelp = true; + break; + } + if (arg == "--help" || arg == "-h") { + printHelp = true; + } else if (arg == "--print-fonts") { + printFonts = true; + } else if (arg == "--font-path") { + optParams = 'f'; + } else if (arg == "--elf") { + optParams = 'e'; + } else if (arg == "--write-labels") { + printLabels = true; + } else if (!arg.empty() && arg[0] == '-') { + cerr << "Unrecognized command line flag " << arg << endl; + return 1; + } else { + positionalArgs.push_back(move(arg)); + } + } + + if (optParams != '\0') { + cerr << "Missing required parameter" << endl; + printHelp = true; + } + + if (printHelp || positionalArgs.size() != 2) { + cerr << "Usage: " << argv[0] << " [--elf ] [--print-fonts] [--font-path ] infile.mus outfile.bin" << endl; + return 1; + } + + string filename = positionalArgs[0]; + Compiler c(fontpath); + ifstream fin; + istream* is; + bool loaded; + + loaded = tryLoadFile("include/sequence.inc", &fin); + if (!loaded) { + loaded = tryLoadFile("sequence.inc", &fin); + if (!loaded) { + cerr << "Warning: sequence.inc not found! Default symbols will not exist while parsing music file." << endl; + } + } + + if (loaded) { + is = &fin; + c.processFile(*is, "sequence.inc"); + fin.close(); + } + + if (filename == "-") { + filename = ""; + is = &cin; + } + + loaded = tryLoadFile(filename, &fin); + if (!loaded) { + cerr << "Failed to open " << filename << endl; + return 1; + } + + is = &fin; + c.processFile(*is, filename); + c.applyFixups(); + + fin.close(); + + string outFilename = positionalArgs[1]; + + if (elf.machine.empty()) { + ofstream fout(outFilename, ios::binary); + c.write(fout); + if (!fout) { + cerr << "Failed to write to output file" << endl; + return 1; + } + } else { + elfio writer; + writer.create(elf.width == 32 ? ELFCLASS32 : ELFCLASS64, + elf.littleEndian ? ELFDATA2LSB : ELFDATA2MSB); + writer.set_abi_version(ELFOSABI_NONE); + writer.set_type(ET_NONE); + writer.set_machine(getMachine(elf.machine, elf.width)); + + section* dataSection = writer.sections.add(".data"); + dataSection->set_type(SHT_PROGBITS); + dataSection->set_flags(SHF_ALLOC | SHF_WRITE); + dataSection->set_addr_align(16); + + stringstream datastream; + c.write(datastream); + while ((datastream.tellp() & 15) != 0) { + datastream.put(0); + } + + dataSection->set_data(datastream.str()); + + segment* dataSegment = writer.segments.add(); + dataSegment->set_type(PT_LOAD); + dataSegment->set_virtual_address(0); + dataSegment->set_physical_address(0); + dataSegment->set_flags(PF_R | PF_W); + dataSegment->set_align(16); + + dataSegment->add_section(dataSection, dataSection->get_addr_align()); + + writer.save(outFilename); + } + + if (printFonts) { + cout << "Cache=" << std::to_string(c.getCachePolicy()) << endl; + for (uint8_t id : c.getFontIds()) { + cout << std::to_string(id) << endl; + } + } + + if (printLabels) { + ofstream of("labels.txt"); + for (auto element : c.getLabels()) { + ostringstream buf; + buf << SectionName.at(element.second.section) << " label called " << element.first << " is located at offset 0x" << std::hex << element.second.offset << endl; + of << buf.str(); + } + } + + return 0; +} diff --git a/tools/assemble_sequences.py b/tools/assemble_sequences.py new file mode 100644 index 00000000000..951181f0014 --- /dev/null +++ b/tools/assemble_sequences.py @@ -0,0 +1,181 @@ +#!/usr/bin/env python3 +from argparse import ArgumentParser +import subprocess +import io +import os +from pathlib import Path +import struct +import sys +import xml.etree.ElementTree as XmlTree +from audio_common import StructPackSpec, parse_machine, toCachePolicy +from makeelf.elf import * + +class SequenceDefinition: + def __init__(self): + self.name = "" + self.size = -1 + self.fonts = [] + self.cachePolicy = 2 + self.ref = None + +def process_sequence_file(sequence, soundfont_path, output_path): + defn = SequenceDefinition() + + defn.name = os.path.basename(sequence) + seq_path = Path(sequence) + + if seq_path.is_symlink(): + defn.ref = seq_path.resolve().relative_to(seq_path.parent) + return defn + + try: + assembleseq = os.path.join(os.path.dirname(__file__), "assemble_sequence") + common_dir = os.getcwd() + rel_assembleseq = "./" + os.path.relpath(assembleseq, common_dir).replace("\\", "/") + sequence_out_path = Path(os.path.join(output_path, seq_path)).with_suffix(".o") + os.makedirs(sequence_out_path.parent, exist_ok=True) + result = subprocess.run([rel_assembleseq, sequence, sequence_out_path, "--font-path", soundfont_path, "--elf", "big", "32", "mips", "--print-fonts"], capture_output=True, text=True) + except subprocess.CalledProcessError: + print(f"Failed to convert {sequence} to binary format", file=sys.stderr) + exit(1) + + fontlines = result.stdout.split("\n") + for line in fontlines: + try: + if line.startswith("Cache="): + defn.cachePolicy = int(line.split("=")[1]) + fontid = int(line) + defn.fonts.append(fontid) + except: + continue + + output_elf = ELF.from_file(sequence_out_path)[0] + data_section = output_elf.get_section_by_name(".data")[0] + defn.size = data_section.sh_size + + return defn + +def process_sequence_files(sequence_path, soundfont_path, output_path): + result = [] + + for file in os.listdir(sequence_path): + if file.endswith(".seq"): + result.append(process_sequence_file(os.path.join(sequence_path, file), soundfont_path, output_path)) + + refpath = os.path.join(args.sequences, "References.xml") + refxml = XmlTree.parse(refpath) + + for reference in refxml.getroot().findall("Reference"): + defn = SequenceDefinition() + defn.name = reference.get("Name") + defn.ref = reference.get("Target") + defn.cachePolicy = toCachePolicy(reference.get("CachePolicy", default="Temporary")) + result.append(defn) + + result = sorted(result, key=lambda defn: os.path.basename(defn.name)) + return result + +def get_seq_index(refname, seqdefs): + for i in range(len(seqdefs)): + defn = seqdefs[i] + if defn.name.endswith(refname): + return i + + raise Exception(f"Sequence {refname} not found but referenced") + +def generate_sequence_table(sequences, output_path, machine, packspecs): + with open(os.path.join(output_path, "assets", "data", "SequenceTable.o"), "wb") as seqtable: + stream = io.BytesIO() + stream.write(struct.pack(packspecs.genPackString("H14x"), len(sequences))) + start_offset = 0 + for defn in sequences: + spec = packspecs.genPackString("IIbbxxxxxx") + if defn.ref: + packed = struct.pack(spec, get_seq_index(defn.ref, sequences), 0, 2, defn.cachePolicy) + else: + packed = struct.pack(spec, start_offset, defn.size, 2, defn.cachePolicy) + start_offset += defn.size + stream.write(packed) + + elf = ELF( + e_class=ELFCLASS.ELFCLASS64 if packspecs.is_64 else ELFCLASS.ELFCLASS32, + e_data=ELFDATA.ELFDATA2LSB if packspecs.le else ELFDATA.ELFDATA2MSB, + e_type=ET.ET_REL, + e_machine=machine + ) + data = elf._append_section(".data", stream.getvalue(), 0, sh_flags=SHF.SHF_ALLOC | SHF.SHF_WRITE, sh_addralign=16, sh_entsize=1) + elf.append_symbol(".data", data, 0, stream.getbuffer().nbytes, STB.STB_LOCAL, STT.STT_SECTION, STV.STV_DEFAULT) + elf.append_symbol("_SequenceTable_start", data, 0, 0, STB.STB_GLOBAL, STT.STT_OBJECT, STV.STV_DEFAULT) + elf.append_symbol("gSequenceTable", data, 0, stream.getbuffer().nbytes, STB.STB_GLOBAL, STT.STT_OBJECT, STV.STV_DEFAULT) + elf.append_symbol("_SequenceTable_end", data, stream.getbuffer().nbytes, 0, STB.STB_GLOBAL, STT.STT_OBJECT, STV.STV_DEFAULT) + seqtable.write(bytes(elf)) + +def generate_sequence_font_table(sequences, output_path, machine, packspecs): + with open(os.path.join(output_path, "assets", "data", "SequenceFontTable.o"), "wb") as seqmap: + stream = io.BytesIO() + seqoffsets = {} + + for i in range(len(sequences)): + defn = sequences[i] + seqoffsets[i] = stream.tell() + (len(sequences) * 2) + if defn.ref: + defn = sequences[get_seq_index(defn.ref, sequences)] + stream.write(struct.pack(packspecs.genPackString("b"), len(defn.fonts))) + for id in defn.fonts: + stream.write(struct.pack(packspecs.genPackString("b"), id)) + + stream.seek(0) + + for offset in seqoffsets.values(): + stream.write(struct.pack(packspecs.genPackString("H"), offset)) + for defn in sequences: + if defn.ref: + defn = sequences[get_seq_index(defn.ref, sequences)] + stream.write(struct.pack(packspecs.genPackString("b"), len(defn.fonts))) + for id in defn.fonts: + stream.write(struct.pack(packspecs.genPackString("b"), id)) + + while stream.getbuffer().nbytes & 0xF != 0: + stream.write(struct.pack(packspecs.genPackString("b"), 0)) + + elf = ELF( + e_class=ELFCLASS.ELFCLASS64 if packspecs.is_64 else ELFCLASS.ELFCLASS32, + e_data=ELFDATA.ELFDATA2LSB if packspecs.le else ELFDATA.ELFDATA2MSB, + e_type=ET.ET_REL, + e_machine=machine + ) + data = elf._append_section(".data", stream.getvalue(), 0, sh_flags=SHF.SHF_ALLOC, sh_addralign=16) + elf.append_symbol(".data", data, 0, 0, STB.STB_LOCAL, STT.STT_SECTION, STV.STV_DEFAULT) + elf.append_symbol("_SequenceFontTable_start", data, 0, 0, STB.STB_GLOBAL, STT.STT_OBJECT, STV.STV_DEFAULT) + elf.append_symbol("gSequenceFontTable", data, 0, 0, STB.STB_GLOBAL, STT.STT_OBJECT, STV.STV_DEFAULT) + elf.append_symbol("_SequenceFontTable_end", data, stream.getbuffer().nbytes, 0, STB.STB_GLOBAL, STT.STT_OBJECT, STV.STV_DEFAULT) + seqmap.write(bytes(elf)) + +def main(args): + packspecs = StructPackSpec(args.le, args.arch64) + if args.machine: + machine = parse_machine(args.machine[0]) + + if not args.sequences.is_dir(): + print("Sequence asset path does not exist or is not a directory.", file=sys.stderr) + return 1 + + if not args.output.is_dir(): + print("Output path does not exist or is not a directory.", file=sys.stderr) + return 1 + + sequences = process_sequence_files(args.sequences,args.soundfonts, args.output) + + generate_sequence_table(sequences, args.output, machine, packspecs) + generate_sequence_font_table(sequences, args.output, machine, packspecs) + +if __name__ == "__main__": + parser = ArgumentParser(add_help=False) + parser.add_argument("sequences", metavar="", type=Path, help="The path to sequence assets.") + parser.add_argument("soundfonts", metavar="", type=Path, help="The path to the soundfont include files.") + parser.add_argument("output", metavar="", type=Path, help="The path to where built machine files should be stored.") + parser.add_argument("--little-endian", dest="le", action="store_true", help="Use this flag if building for Little-Endian target. Overrides --match and --debug") + parser.add_argument("--64", dest="arch64", action="store_true", help="Use this flag if building for 64-bit target. (Importantly, this does NOT include N64 itself). Overrides --match and --debug") + parser.add_argument("--machine", nargs=1, required=False, default=["mips"], help="The machine type to use for the output ELF files.") + args = parser.parse_args() + main(args) diff --git a/tools/assemble_sound.py b/tools/assemble_sound.py new file mode 100644 index 00000000000..4453838c9b8 --- /dev/null +++ b/tools/assemble_sound.py @@ -0,0 +1,1151 @@ +#!/usr/bin/env python3 +import argparse +import os +from pathlib import Path +import struct +import sys +import tempfile + +import xml.etree.ElementTree as XmlTree + +from makeelf.elf import * +from audio_common import * + +# Script variables +debug_mode = False +match_mode = None +target_le = False +target_64 = False +packspecs = StructPackSpec() + +bank_lookup = {} +banks = [] +font_lookup = {} + +last_font_match_sizes = { + "ocarina" : 0x12B60, + "ocarina1_0" : 0x3940, + "majora" : 0x3F0 +} + +audiobank_sizes = { + "ocarina" : 0x2BDC0, + "ocarina1_0" : 0x1CA50, + "majora" : 0x263F0 +} + +class DrumOffsetTable: + def __init__(self): + self.off_list = [] + self.addr = -1 + + def serializeTo(self, output, packspecs=StructPackSpec()): + sz = 0 + for off in self.off_list: + output.write(struct.pack(packspecs.genPackString("P"), off)) + sz += packspecs.pointerSize() + return sz + +class DummyBlock: + def __init__(self, size_in_bytes): + self.size = size_in_bytes + self.addr = -1 + + def serializeTo(self, output, packspecs=StructPackSpec()): + output.write(struct.pack(packspecs.genPackString(str(self.size) + "x"))) + return self.size + +class GarbageBlock: + def __init__(self): + self.data = [] + self.addr = -1 + + def serializeTo(self, output, packspecs=StructPackSpec()): + if self.data: + for i in range(len(self.data)): + output.write(struct.pack(packspecs.genPackString("B"), self.data[i])) + return len(self.data) + +def checkMatch(refData, checkData, nameStr): + # Sees if match. If so, print message saying so. If not, give offset of first mismatched byte + # Return boolean (so can count) + if nameStr is None: + nameStr = "ANON_CHECK" + if refData is None: + print(f"MATCH {nameStr}: Please provide reference data for matching") + return False + if checkData is None: + print(f"MATCH {nameStr}: Please provide target data for matching") + return False + + offset = 0 + rlen = len(refData) + tlen = len(checkData) + maxlen = min(rlen, tlen) + + # Obviously if lengths don't match, there's not a match, but I still want to check offset + for i in range(maxlen): + if refData[i] != checkData[i]: + print(f"MATCH {nameStr}: Mismatch found @ 0x{offset:08x}") + return False + offset += 1 + + if rlen != tlen: + print(f"MATCH {nameStr}: Mismatch found @ 0x{offset:08x}") + return False + + print(f"MATCH {nameStr}: Target matches reference!") + return True + +def orderWaveBlocksInstOrder(font, ser_blocks, base_addr): + slist = [] + + slots = font.instSlotCount() + for i in range(slots): + if i in font.instIdxLookup: + inst = font.instIdxLookup[i] + if inst.keyLowSample: + if inst.keyLowSample not in slist: + slist.append(inst.keyLowSample) + if inst.keyMedSample: + if inst.keyMedSample not in slist: + slist.append(inst.keyMedSample) + if inst.keyHighSample: + if inst.keyHighSample not in slist: + slist.append(inst.keyHighSample) + + slots = font.percSlotCount() + for i in range(slots): + if i in font.percIdxLookup: + drum = font.percIdxLookup[i] + if drum.sample: + if drum.sample not in slist: + slist.append(drum.sample) + + slots = font.sfxSlotCount() + for i in range(slots): + if i in font.sfxIdxLookup: + sfx = font.sfxIdxLookup[i] + if sfx.sample: + if sfx.sample not in slist: + slist.append(sfx.sample) + + for sample in slist: + sample.addr = -1 + if sample.loop: + sample.loop.addr = -1 + if sample.book: + sample.book.addr = -1 + + block_size = 16 + if target_64: + block_size = 32 + current_addr = base_addr + for sample in slist: + ser_blocks.append(sample) + sample.addr = current_addr + current_addr += block_size + + # Add book if not added + if sample.book and (sample.book.addr < 0): + ser_blocks.append(sample.book) + sample.book.addr = current_addr + current_addr += (sample.book.order * sample.book.predictorCount * 16) + 8 + current_addr = align(current_addr, 16) + + if sample.loop and (sample.loop.addr < 0): + ser_blocks.append(sample.loop) + sample.loop.addr = current_addr + if sample.loop.count != 0: + current_addr += 48 + else: + current_addr += 16 + + return current_addr + +def orderWaveBlocksBankOrder(font, ser_blocks, base_addr): + # Extract all used blocks from the font (ugh) + s_dict = {} + for inst in font.instruments: + if inst.keyLowSample and inst.keyLowSample.idx not in s_dict: + s_dict[inst.keyLowSample.idx] = inst.keyLowSample + if inst.keyMedSample and inst.keyMedSample.idx not in s_dict: + s_dict[inst.keyMedSample.idx] = inst.keyMedSample + if inst.keyHighSample and inst.keyHighSample.idx not in s_dict: + s_dict[inst.keyHighSample.idx] = inst.keyHighSample + + for drum in font.percussion: + if drum.sample: + if drum.sample.idx not in s_dict: + s_dict[drum.sample.idx] = drum.sample + + for sfx in font.soundEffects: + if sfx.sample and sfx.sample.idx not in s_dict: + s_dict[sfx.sample.idx] = sfx.sample + + dict_items = sorted(s_dict.items()) + for item in dict_items: + # Clear Addresses + sample = item[1] + sample.addr = -1 + if sample.loop: + sample.loop.addr = -1 + if sample.book: + sample.book.addr = -1 + + # Iterate again, this time using blank addresses to check for addition + block_size = 16 + if target_64: + block_size = 32 + current_addr = base_addr + for item in dict_items: + sample = item[1] + ser_blocks.append(sample) + sample.addr = current_addr + current_addr += block_size + + # Add book if not added + if sample.book and (sample.book.addr < 0): + ser_blocks.append(sample.book) + sample.book.addr = current_addr + current_addr += (sample.book.order * sample.book.predictorCount * 16) + 8 + current_addr = align(current_addr, 16) + + if sample.loop and (sample.loop.addr < 0): + ser_blocks.append(sample.loop) + sample.loop.addr = current_addr + if sample.loop.count != 0: + current_addr += 48 + else: + current_addr += 16 + + return current_addr + +def orderWaveBlocksMatchOrder(font, ser_blocks, base_addr): + slist = [] + + for stuple in font.sampleOrder: + fname = stuple[1] + if fname in font.bank1.samplesByName: + slist.append(font.bank1.samplesByName[fname]) + + for sample in slist: + sample.addr = -1 + if sample.loop: + sample.loop.addr = -1 + if sample.book: + sample.book.addr = -1 + + block_size = 16 + if target_64: + block_size = 32 + + current_addr = base_addr + for sample in slist: + ser_blocks.append(sample) + sample.addr = current_addr + current_addr += block_size + + # Add book if not added + if sample.book and (sample.book.addr < 0): + ser_blocks.append(sample.book) + sample.book.addr = current_addr + current_addr += (sample.book.order * sample.book.predictorCount * 16) + 8 + current_addr = align(current_addr, 16) + + if sample.loop and (sample.loop.addr < 0): + ser_blocks.append(sample.loop) + sample.loop.addr = current_addr + if sample.loop.count != 0: + current_addr += 48 + else: + current_addr += 16 + + return current_addr + +def orderEnvelopeBlocks(font, ser_blocks, base_addr): + # Scan inst and perc to make sure all envelopes are in font map + for inst in font.instruments: + if inst.envelope and not inst.envelope.name in font.envelopes: + font.envelopes[inst.envelope.name] = inst.envelope + + for drum in font.percussion: + if drum.envelope and not drum.envelope.name in font.envelopes: + font.envelopes[drum.envelope.name] = drum.envelope + + # Nab envelopes from font + eitems = sorted(font.envelopes.items()) + + current_addr = base_addr + for eitem in eitems: + env = eitem[1] + ser_blocks.append(env) + env.addr = current_addr + current_addr += env.serialSize() + current_addr = align(current_addr, 16) + + return current_addr + +def compileFont(font, output, audiobank_off=0): + # Blocks appear to be in the following order: + # Wave Info (In order they appear in bank) + # ADPCM Book (If not identical to one in previous wave) + # Loop (If not identical to one in previous wave) + # Envelopes (Seem to be in order they are referenced?) + # Instruments (NOT in index order. Probably order they were added.) + # Drums (Usually in index order, but I don't think that's guaranteed) + # Drum Offset Table + # SFX Table (By index - 0L if empty slot) + + # Starts after head offset table + ser_blocks = [] + + # Get used slot counts + icount = font.instSlotCount() + pcount = font.percSlotCount() + xcount = font.sfxSlotCount() + + # Calculate head offset table size + current_pos = (2 + icount) * packspecs.pointerSize() + current_pos = align(current_pos, 16) + + # Wave blocks + if match_mode: + if font.sampleOrder and len(font.sampleOrder) > 0: + current_pos = orderWaveBlocksMatchOrder(font, ser_blocks, current_pos) + else: + current_pos = orderWaveBlocksBankOrder(font, ser_blocks, current_pos) + else: + current_pos = orderWaveBlocksBankOrder(font, ser_blocks, current_pos) + + # Envelope blocks + current_pos = orderEnvelopeBlocks(font, ser_blocks, current_pos) + + # Instrument blocks + block_size = 32 + if target_64: + block_size = 64 + for inst in font.instruments: + ser_blocks.append(inst) + inst.addr = current_pos + current_pos += block_size + + # Drum blocks + block_size = 16 + + if target_64: + block_size = 32 + + if pcount > 0: + for drum in font.percussion: + ser_blocks.append(drum) + drum.addr = current_pos + current_pos += block_size + + # Drum offset table + drum_offtbl = DrumOffsetTable() + drum_offtbl.addr = current_pos + + for i in range(pcount): + if i in font.percIdxLookup: + drum_offtbl.off_list.append(font.percIdxLookup[i].addr) + else: + drum_offtbl.off_list.append(0) + current_pos += packspecs.pointerSize() + + current_pos = align(current_pos, 16) + ser_blocks.append(drum_offtbl) + else: + drum_offtbl = DrumOffsetTable() + drum_offtbl.addr = 0 + + # SFX table + block_size = 8 + + if target_64: + block_size = 16 + + if xcount > 0: + sfx_tbl_pos = current_pos + + for i in range(xcount): + if i in font.sfxIdxLookup: + mysfx = font.sfxIdxLookup[i] + mysfx.addr = current_pos + ser_blocks.append(mysfx) + else: + dummysfx = DummyBlock(block_size) + dummysfx.addr = current_pos + ser_blocks.append(dummysfx) + current_pos += block_size + else: + sfx_tbl_pos = 0 + + # If in match mode, insert garbage data + if match_mode: + for item in font.unusedDat.items(): + dat_off = item[0] + unused_data = item[1] + sblock = GarbageBlock() + sblock.data = bytes(unused_data) + sblock.addr = dat_off - audiobank_off + + # Insert :( + ct = len(ser_blocks) + inserted = False + mysize = len(unused_data) + + for i in range(ct): + ser_block = ser_blocks[i] + if ser_block.addr >= sblock.addr: + if not inserted: + ser_blocks.insert(i, sblock) + inserted = True + else: + ser_block.addr += mysize + + if inserted: + ser_blocks[ct].addr += mysize # Last block that was pushed down + else: + # Append + ser_blocks.append(sblock) + + # Serialize the head offset table + output.write(struct.pack(packspecs.genPackString("PP"), drum_offtbl.addr, sfx_tbl_pos)) + wpos = packspecs.pointerSize() << 1 + for i in range(icount): + if i in font.instIdxLookup: + myinst = font.instIdxLookup[i] + output.write(struct.pack(packspecs.genPackString("P"), myinst.addr)) + else: + output.write(struct.pack(f"{packspecs.pointerSize()}x")) + wpos += packspecs.pointerSize() + + # Write everything else + for block in ser_blocks: + # Pad if needed + padding = block.addr - wpos + if padding > 0: + output.write(struct.pack(str(padding) + "x")) + wpos += padding + # Serialize block + wpos += block.serializeTo(output, packspecs) + + # Pad to end, if needed + padding = align(wpos,16) - wpos + if padding > 0: + output.write(struct.pack(str(padding) + "x")) + wpos += padding + + return wpos + +def linkFontToBank(font): + # This links the sound info to the font + if not font.bankNames: + return + + bname = font.bankNames[0] + if not bname: + return + + if bname in bank_lookup: + mybank = bank_lookup[bname] + font.bankIdx1 = mybank.idx + else: + # Try to isolate index from name... + if bname[0:1].isnumeric(): + firstspace = bname.find(' ') + bidx = int(bname[:firstspace]) + mybank = banks[bidx] + font.bankIdx1 = bidx + if not mybank: + print(f"WARNING: Could not find bank match {bname} for font: {font.name}", file=sys.stderr) + return + else: + print(f"WARNING: Could not find bank match {bname} for font: {font.name}", file=sys.stderr) + return + + if not mybank: + print(f"WARNING: Could not find bank match {bname} for font: {font.name}", file=sys.stderr) + return + + # Check for apparent bank if in match mode + if match_mode and len(font.apparent_banks) > 0: + abname = font.apparent_banks[0] + if abname in bank_lookup: + abank = bank_lookup[abname] + font.bankIdx1 = abank.idx + else: + # Try to isolate index from name... + if abname[0:1].isnumeric(): + firstspace = abname.find(' ') + abidx = int(abname[:firstspace]) + abank = banks[abidx] + font.bankIdx1 = abidx + if not abank: + print(f"WARNING: Could not find bank match {abname} for font: {font.name}", file=sys.stderr) + else: + print(f"WARNING: Could not find bank match {abname} for font: {font.name}", file=sys.stderr) + + # Link bank and samples + font.bank1 = mybank + for inst in font.instruments: + if inst.keyLowName: + inst.keyLowSample = mybank.getSample(inst.keyLowName) + if inst.keyLowSample is not None and inst.keyLowPitch < 0.0: + inst.keyLowPitch = inst.keyLowSample.tuning + if inst.keyMedName: + inst.keyMedSample = mybank.getSample(inst.keyMedName) + if inst.keyMedSample is not None and inst.keyMedPitch < 0.0: + inst.keyMedPitch = inst.keyMedSample.tuning + if inst.keyHighName: + inst.keyHighSample = mybank.getSample(inst.keyHighName) + if inst.keyHighSample is not None and inst.keyHighPitch < 0.0: + inst.keyHighPitch = inst.keyHighSample.tuning + + for drum in font.percussion: + if drum.sampleName: + drum.sample = mybank.getSample(drum.sampleName) + if drum.sample is not None and drum.pitch < 0.0: + drum.pitch = drum.sample.tuning + + for sfx in font.soundEffects: + if sfx.sampleName: + sfx.sample = mybank.getSample(sfx.sampleName) + if sfx.sample is not None and sfx.pitch < 0.0: + sfx.pitch = sfx.sample.tuning + +def getFileName(idx=None, name=""): + name = f"{idx}_{name}" if idx is not None else name + return ''.join('_' if c not in 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_' else c for c in name) + +def readFonts(dirpath): + for file in os.listdir(dirpath): + if file.endswith(".xml"): + readFont(os.path.join(dirpath, file)) + +def readFont(filepath): + filename = os.path.basename(filepath) + if debug_mode: + print("Reading soundfont xml: ", filename) + fontname = filename[:-4] + myfont = Soundfont() + + xmltree = XmlTree.parse(filepath) + xmlroot = xmltree.getroot() + if xmlroot.tag == "Soundfont": + sfnode = xmlroot + else: + sfnode = xmlroot.find("Soundfont") + + if sfnode is None: + print(f"ERROR - could not find Soundfont definition in: {filename}", file=sys.stderr) + exit(1) + + myfont.fromXML(sfnode) + + # Resolve font name, and index if part of name + if fontname[0:1].isnumeric(): + spaceidx = fontname.find('_') + if spaceidx >= 0: + myfont.idx = int(fontname[:spaceidx]) + fontname = fontname[spaceidx + 1:] + + font_lookup[fontname] = myfont + myfont.name = fontname + + # Link samples + linkFontToBank(myfont) + +def printBank2csv(path, bank): + csvstream = open(path, 'w') + csvstream.write('# Index,Name,Codec,Medium,u2,OffsetInBank,Length,FrameCount,Tuning\n') + + samplelist = bank.samples + for sample in samplelist: + csvstream.write(f"{sample.idx},") + csvstream.write(f"{sample.name.replace(',', '')},") + csvstream.write(f"{toCodecID(sample.codec)},") + csvstream.write(f"{toMedium(sample.medium)},") + csvstream.write(f"{sample.u2},") + csvstream.write(f"0x{sample.offsetInBank:0>8x},") + csvstream.write(f"0x{sample.length:0>8x},") + csvstream.write(f"{sample.frameCount},") + csvstream.write(f"{sample.tuning}\n") + + csvstream.close() + +def splitSampleName(filepath): + rawname = filepath + # Chop extension + if filepath.endswith(".aifc"): + rawname = filepath[:-5] + + # Check for number + inum = -1 + sname = rawname + firstchar = rawname[0:1] + if firstchar.isnumeric(): + # Find the first space + firstspace = rawname.find(' ') + if firstspace >= 0: + istr = rawname[:firstspace] + sname = rawname[firstspace + 1:] + inum = int(istr) + + # Return number, name + return (inum, sname) + +def get_sym_name(name): + result = '' + for c in name: + # Only keep letters, digits, and underscores + if c in 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_': + result += c + # Replace everything else with underscores + else: + result += '_' + + # Symbols can't start with numbers + if result[0:1] in '1234567890': + result = '_' + result + + return result + +def processBanks(sampledir, builddir, tabledir): + xmltree = XmlTree.parse(os.path.join(sampledir, "Banks.xml")) + xmlroot = xmltree.getroot() + + if builddir is not None: + os.makedirs(builddir, exist_ok=True) + + if xmlroot.tag == "SampleBanks": + e_banks = xmlroot + else: + e_banks = xmlroot.find("SampleBanks") + if e_banks is None: + print("Banks.xml does not appear to be valid", file=sys.stderr) + return + elist_bank = e_banks.findall("SampleBank") + + i = 0 + audiotable_paths = [] + + for e_bank in elist_bank: + bankname = e_bank.get("Name") + if bankname is None: + bankname = f"{i} - REF" + mybank = bank_lookup[e_bank.get("Reference")] + bank_lookup[bankname] = mybank + if not quiet: + print("Bank reference discovered:", bankname) + audiotable_paths.append(None) + banks.append(mybank) + else: + if not quiet: + print("Bank discovered:", bankname) + mybank = Soundbank() + banks.append(mybank) + mybank.name = bankname + mybank.fromXML(e_bank) + bank_lookup[bankname] = mybank + + mybank.idx = i + bankdir = os.path.join(sampledir, bankname) + + current_books = [] + current_loops = [] + index_map = {} + max_idx = -1 + need_index = [] + + for file in os.listdir(bankdir): + if file.endswith(".aifc"): + tup = splitSampleName(file) + si = tup[0] + samplename = tup[1] + mysample = SampleHeader() + if samplename in mybank.samplesByName: + print("WARNING: Duplicate sample key found:", samplename, file=sys.stderr) + mybank.samplesByName[samplename] = mysample + mysample.name = samplename + mysample.idx = si + mysample.fileName = file + + if si < 0: + need_index.append(mysample) + else: + index_map[si] = mysample + if si > max_idx: + max_idx = si + + # load from aifc + mysample.loadInfoFromAif(os.path.join(bankdir, file)) + + # If book or loop is identical to previous in bank, merge. + blmerge = False + if mysample.book is not None: + for book in current_books: + if book.booksEqual(mysample.book): + blmerge = True + mysample.book = book + break + if not blmerge: + current_books.append(mysample.book) + + if not match_mode: + # Looks like original tool does not merge (the very rare, but existing) identical loops + blmerge = False + if mysample.loop is not None: + for loop in current_loops: + if loop.loopsEqual(mysample.loop): + blmerge = True + mysample.loop = loop + break + if not blmerge: + current_loops.append(mysample.loop) + + # Assign indices to yet unindexed samples. + nextidx = 0 + for asample in need_index: + while nextidx in index_map: + nextidx += 1 + asample.idx = nextidx + index_map[nextidx] = asample + max_idx = max(max_idx, nextidx) + nextidx += 1 + + # Order samples. + c = 0 + while c <= max_idx: + if c in index_map: + mysample = index_map[c] + mybank.samples.append(mysample) + else: + mybank.samples.append(None) + c += 1 + + # Now, assign offsets/calculate sizes for samples + sorted_samples = mybank.samples + if not quiet: + print(f"Bank {mybank.idx}: {len(sorted_samples)} samples found") + + binpath = None + opath = None + syms = [] + if builddir is not None: + opath = os.path.join(builddir, f"{getFileName(name=mybank.name)}.o") + if len(sorted_samples) > 0: + output = None + if builddir is not None: + output = tempfile.NamedTemporaryFile("wb", prefix="bank_", suffix=f"_{mybank.idx}.bank.tmp", delete=False) + binpath = output.name + audiotable_paths.append(binpath) + + j = 0 + offset = 0 + for sample in sorted_samples: + sample.idx = j + j += 1 + sample.offsetInBank = offset + # Need to add padding as well... + offset += sample.length + padding = padding16(offset) + offset += padding + + if output is not None: + if not quiet: + print("Writing sample:", sample.name) + aifc_path = os.path.join(bankdir, sample.fileName) + syms.append( + ( + get_sym_name(sample.name), + output.tell(), + 4, + STB.STB_GLOBAL, + STT.STT_OBJECT, + STV.STV_DEFAULT + ) + ) + output.write(loadSoundData(aifc_path)[8:8 + sample.length]) + if padding > 0: + output.write(struct.pack(f"{padding}x")) + + if output is not None: + output.close() + output = None + + if (builddir is not None) and (mybank.idx == 0) and match_mode: + # There appears to be a buffer clearing bug in the original authoring tool + # that only affects the end of bank 0. + # Must replicate to get a match + filesize = os.path.getsize(binpath) + temppath = binpath + ".tmp" + os.rename(binpath, temppath) + with open(temppath, "rb") as input: + with open(binpath, "wb") as output: + bug_trg = filesize - 4 + bug_src = bug_trg - 0x10000 + output.write(input.read(bug_src)) + bug_word = input.read(4) + output.write(bug_word) + output.write(input.read(0xFFFC)) + output.write(bug_word) + Path(temppath).unlink(missing_ok=True) + else: + # If no aifc files were found, look for raw bin + for file in os.listdir(bankdir): + if file.endswith(".bin"): + binpath = os.path.join(bankdir, file) + audiotable_paths.append(binpath) + break + elftable = ELF( + e_class=ELFCLASS.ELFCLASS64 if target_64 else ELFCLASS.ELFCLASS32, + e_data=ELFDATA.ELFDATA2LSB if target_le else ELFDATA.ELFDATA2MSB, + e_type=ET.ET_REL, + e_machine=machine + ) + with open(binpath, "rb") as datafile: + with open(opath, "wb") as elffile: + bankdata = datafile.read() + data = elftable._append_section(".data", bankdata, 0, sh_flags=SHF.SHF_ALLOC | SHF.SHF_WRITE, sh_addralign=16) + elftable.append_symbol(get_sym_name(bankname + "_start"), data, 0, 4, STB.STB_GLOBAL, STT.STT_OBJECT) + for name, value, size, binding, type, visibility in syms: + elftable.append_symbol( + name, + data, + value, + size, + binding, + type, + visibility + ) + elftable.append_symbol(get_sym_name(bankname + "_end"), data, len(bankdata), 4, STB.STB_GLOBAL, STT.STT_OBJECT) + elffile.write(bytes(elftable)) + + i += 1 + + # Code table + banktable_path = None + with tempfile.NamedTemporaryFile("wb", prefix="SampleBankTable", suffix=".tmp", delete=False) as output: + banktable_path = output.name + bnk_ordered = sorted(bank_lookup.items()) + output.write(struct.pack(packspecs.genPackString("H14x"), len(bnk_ordered))) + i = 0 + offset = 0 + for bnk_pair in bnk_ordered: + mybank = bnk_pair[1] + if mybank.idx == i: + if debug_mode: + # Print csv stating what samples are in bank. + printBank2csv(os.path.join(tabledir, getBankbinName(mybank.idx) + "_contents.csv"), mybank) + banklen = mybank.calculateSize() + if banklen <= 0: + # Check for bin. + banklen = os.path.getsize(audiotable_paths[mybank.idx]) + output.write(struct.pack(packspecs.genPackString("LL"), offset, banklen)) + offset += banklen + else: + output.write(struct.pack("8x")) + output.write(struct.pack(packspecs.genPackString("BB6x"), mybank.medium, mybank.cachePolicy)) + i += 1 + + for tmpbank in audiotable_paths: + if tmpbank and tmpbank.endswith(".tmp"): + Path(tmpbank).unlink(missing_ok=True) + + os.makedirs(tabledir, exist_ok=True) + with open(os.path.join(tabledir, "SampleBankTable.o"), "wb") as elftblfile: + with open(banktable_path, "rb") as tblfile: + elf = ELF( + e_class=ELFCLASS.ELFCLASS64 if target_64 else ELFCLASS.ELFCLASS32, + e_data=ELFDATA.ELFDATA2LSB if target_le else ELFDATA.ELFDATA2MSB, + e_type=ET.ET_REL, + e_machine=machine + ) + sampledata = tblfile.read() + data = elf._append_section(".data", sampledata, 0, sh_flags=SHF.SHF_ALLOC | SHF.SHF_WRITE, sh_addralign=16) + elf.append_symbol(".data", data, 0, len(sampledata), STB.STB_LOCAL, STT.STT_SECTION, STV.STV_DEFAULT) + elf.append_symbol("gSampleBankTable_start", data, 0, 0, STB.STB_GLOBAL, STT.STT_OBJECT, STV.STV_DEFAULT) + elf.append_symbol("gSampleBankTable", data, 0, len(sampledata), STB.STB_GLOBAL, STT.STT_OBJECT, STV.STV_DEFAULT) + elf.append_symbol("gSampleBankTable_end", data, len(sampledata), 0, STB.STB_GLOBAL, STT.STT_OBJECT, STV.STV_DEFAULT) + elftblfile.write(bytes(elf)) + + Path(banktable_path).unlink(missing_ok=True) + +def write_soundfont_define(font, fontcount, filename): + width = int(math.log10(fontcount)) + 1 + index = str(font.idx).zfill(width) + + with open(filename, "w") as file: + file.write("# Soundfont file constants\n") + file.write(f"# ID: {font.idx}\n") + file.write(f"# Name: {font.name}\n") + file.write("\n##### INSTRUMENTS #####\n") + + for instrument in font.instruments: + if instrument is None: + continue + + file.write(f".define FONT{index}_INSTR_{instrument.enum} {instrument.idx}\n") + + file.write("\n##### DRUMS #####\n") + for drum in font.percussion: + if drum is None: + continue + + file.write(f".define FONT{index}_DRUM_{drum.enum} {drum.idx}\n") + + file.write("\n##### EFFECTS #####\n") + for effect in font.soundEffects: + if effect is None: + continue + + file.write(f".define FONT{index}_EFFECT_{effect.enum} {effect.idx}\n") + +def main(args): + global debug_mode + global match_mode + global target_le + global target_64 + global machine + global packspecs + global quiet + + if args.little_endian: + target_le = True + packspecs.byte_order_char = "<" + if args.arch64: + target_64 = True + packspecs.is_64 = True + if args.machine: + machine = parse_machine(args.machine) + + if args.debug and not args.quiet: + debug_mode = True + if args.match and not target_64 and not target_le: + match_mode = args.match + quiet = args.quiet + + outpath = args.outpath + inpath = args.inpath + sampledir = args.sampledir + + if debug_mode: + print("DEBUG MODE:") + print("Input Directory:", inpath) + print("Output Directory:", outpath) + print("Sample Directory:", sampledir) + print("Match Mode:", match_mode) + + # Check for directories' existence + if args.single: + if not os.path.isfile(inpath): + print(f"ERROR: Input file \"{inpath}\" does not exist!", file=sys.stderr) + return 1 + else: + if not os.path.isdir(inpath): + print(f"ERROR: Input path \"{inpath}\" is not a valid directory!", file=sys.stderr) + return 1 + + if not os.path.isdir(sampledir): + print(f"ERROR: Sample path \"{sampledir}\" is not a valid directory!", file=sys.stderr) + return 1 + + if not os.path.isdir(outpath): + os.makedirs(outpath) + + # Process banks and build sample info blocks + bankbuilddir = None + tablebuilddir = os.path.join(outpath, 'data') + if args.build_bank: + bankbuilddir = os.path.join(outpath, 'samplebanks') + processBanks(sampledir, bankbuilddir, tablebuilddir) + + # Check bank matches (if requested) + mydir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + + if debug_mode and args.build_bank and match_mode: + # Find reference files. + bankdat_path = os.path.join("baserom", "Audiotable") + print("Extracted audiotable ref:", bankdat_path) + + # Iterate + banklist = sorted(bank_lookup.items()) + matchcount = 0 + bankcount = 0 + checked = [] + + for item in banklist: + bank = item[1] + if bank.idx in checked: + print("Bank references already checked bank:", bank.idx) + continue + bankcount += 1 + binoutpath = os.path.join(bankbuilddir, getBankbinName(bank.idx)) + if os.path.isfile(binoutpath): + with open(binoutpath, 'rb') as f: + checkdat = f.read() + if checkMatch(refdat, checkdat, f'Bank {bank.idx}'): + matchcount += 1 + else: + print(f"Bank {bank.idx} found as bin. No need to check.") + matchcount += 1 + checked.append(bank.idx) + + print(f"{matchcount} of {bankcount} banks matched.") + + # Check audiotable itself + binoutpath = os.path.join(bankbuilddir, 'audiotable') + with open(bankdat_path, 'rb') as f: + refdat = f.read() + with open(binoutpath, 'rb') as f: + checkdat = f.read() + if checkMatch(refdat, checkdat, 'audiotable'): + print('SUCCESS: audiotable matches!') + else: + print('ERROR: audiotable does not match!') + + refdat = None + checkdat = None + + # Read in font(s) + if args.single: + readFont(inpath) + else: + readFonts(inpath) + + # compile font(s) + fonts_ordered = [] + font_idict = {} + for pair in font_lookup.items(): + font = pair[1] + font_idict[font.idx] = font + + sorted_fonts = sorted(font_idict.items()) + font_count = len(sorted_fonts) + aboff = 0 + audiobank_dir = os.path.join(outpath, 'soundfonts') + + if not os.path.isdir(audiobank_dir): + os.makedirs(audiobank_dir) + + for pair in sorted_fonts: + fonts_ordered.append(pair[1]) + + fontpaths = {} + + for font in fonts_ordered: + with tempfile.NamedTemporaryFile('wb', prefix=f'Bank{font.idx}_', suffix='.tmp', delete=False) as f: + fontpaths[font.idx] = f.name + compileFont(font, f, aboff) + + aboff += os.path.getsize(fontpaths[font.idx]) + + if match_mode and font.idx == (font_count - 1): + if match_mode not in last_font_match_sizes: + if not quiet: + print(f"Match string \'{match_mode}\' not recognized! Ignoring...") + else: + target_size = last_font_match_sizes[match_mode] + current_size = os.path.getsize(fontpaths[font.idx]) + diff = target_size - current_size + with open(fontpaths[font.idx], 'ab') as f: + f.write(struct.pack(f"{diff}x")) + + + with open(os.path.join(audiobank_dir, f"{getFileName(idx=font.idx, name=font.name)}.o"), "wb") as elffile: + with open(fontpaths[font.idx], "rb") as bin: + elf = ELF( + e_class=ELFCLASS.ELFCLASS64 if target_64 else ELFCLASS.ELFCLASS32, + e_data=ELFDATA.ELFDATA2LSB if target_le else ELFDATA.ELFDATA2MSB, + e_type=ET.ET_REL, + e_machine=machine + ) + fontbytes = bin.read() + fontsym = font.symbol if font.symbol else font.name + data = elf._append_section(".data", fontbytes, 0, sh_flags=SHF.SHF_ALLOC | SHF.SHF_WRITE, sh_addralign=16) + elf.append_symbol(f"{get_sym_name(fontsym)}_start", data, 0, 4, STB.STB_GLOBAL, STT.STT_OBJECT, STV.STV_DEFAULT) + elf.append_symbol(f"{get_sym_name(fontsym)}_end", data, len(fontbytes), 4, STB.STB_GLOBAL, STT.STT_OBJECT, STV.STV_DEFAULT) + elffile.write(bytes(elf)) + + os.makedirs(args.outinclude, exist_ok=True) + inc_filename = os.path.join(args.outinclude, f"{font.idx}.inc") + write_soundfont_define(font, font_count, inc_filename) + + # load table for matching + og_font_dat = None + if debug_mode and match_mode: + fontdat_path = os.path.join(mydir, 'baserom', 'Audiobank') + with open(fontdat_path, "rb") as f: + og_font_dat = f.read() + + # write audiobank & code table (and match banks one by one) + audiobank_tbl_path = os.path.join(outpath, "data", "SoundFontTable.o") + audiobank_tbl_tmp = None + current_pos = 0 + total_fonts = len(fonts_ordered) + font_matches = 0 + + with tempfile.NamedTemporaryFile("wb", prefix="SoundFontTable_", suffix=".tmp", delete=False) as tblfile: + audiobank_tbl_tmp = tblfile.name + tblfile.write(struct.pack(packspecs.genPackString("H14x"), total_fonts)) + + for font in fonts_ordered: + fontsize = os.path.getsize(fontpaths[font.idx]) + + myentry = font.getTableEntry() + myentry.offset = current_pos + myentry.length = fontsize + current_pos += fontsize + myentry.serializeTo(tblfile, packspecs) + + with open(audiobank_tbl_path, "wb") as elftblfile: + with open(audiobank_tbl_tmp, "rb") as tblfile: + elf = ELF( + e_class=ELFCLASS.ELFCLASS64 if target_64 else ELFCLASS.ELFCLASS32, + e_data=ELFDATA.ELFDATA2LSB if target_le else ELFDATA.ELFDATA2MSB, + e_type=ET.ET_REL, + e_machine=machine + ) + bankbytes = tblfile.read() + data = elf._append_section(".data", bankbytes, 0, sh_flags=SHF.SHF_ALLOC | SHF.SHF_WRITE, sh_addralign=16) + elf.append_symbol(".data", data, 0, len(bankbytes), STB.STB_LOCAL, STT.STT_SECTION, STV.STV_DEFAULT) + elf.append_symbol("_gSoundFontTable_start", data, 0, 0, STB.STB_GLOBAL, STT.STT_OBJECT, STV.STV_DEFAULT) + elf.append_symbol("gSoundFontTable", data, 0, len(bankbytes), STB.STB_GLOBAL, STT.STT_OBJECT, STV.STV_DEFAULT) + elf.append_symbol("_gSoundFontTable_end", data, len(bankbytes), 0, STB.STB_GLOBAL, STT.STT_OBJECT, STV.STV_DEFAULT) + elftblfile.write(bytes(elf)) + + # match audiobank + if debug_mode and match_mode: + print(f"{font_matches} of {total_fonts} fonts matched.") + + with open(audiobank_tbl_tmp, "rb") as audiobank_file: + abdat = audiobank_file.read() + + checkMatch(og_font_dat, abdat, "audiobank") + + Path(audiobank_tbl_tmp).unlink(missing_ok=True) + for path in fontpaths.values(): + Path(path).unlink(missing_ok=True) + + return 0 + +if __name__ == "__main__": + # Args + parser = argparse.ArgumentParser(add_help=False) + parser.add_argument("inpath", type=Path, help="Input path. If --single, this should be a font xml. If batch, this should be a directory of font xmls.") + parser.add_argument("outpath", type=Path, help="Output path. This should be the directory where target bins are written.") + parser.add_argument("outinclude", type=Path, help="Output path for generated include headers.") + parser.add_argument("sampledir", type=Path, help="Path to file containing sound samples.") + parser.add_argument("--match", help="Aim to build match to original ROM (less efficient, more bookkeeping). Recognized values: ocarina, ocarina1_0, majora") + parser.add_argument("--debug", action="store_true", help="Flag for debug mode (increased verbosity, output matching)") + parser.add_argument("--single", action="store_true", help="Use this flag if only want to build a single font (inputting one xml file)") + parser.add_argument("--build-bank", action="store_true", help="Use this flag to build bank files as well as fonts. Highly recommended.") + parser.add_argument("--little-endian", action="store_true", help="Use this flag if building for Little-Endian target. Overrides --match and --debug") + parser.add_argument("--arch64", action="store_true", help="Use this flag if building for 64-bit target. (Importantly, this does NOT include N64 itself). Overrides --match and --debug") + parser.add_argument("--machine", nargs=1, required=False, default="mips", help="The machine type to use for the output ELF files.") + parser.add_argument("--quiet", "-q", action="store_true", help="Suppresses output to standard out.") + parser.add_argument("--help", "-h", "-?", action="help", help="Show this help message and exit.") + args = parser.parse_args() + main(args) diff --git a/tools/audio_common.py b/tools/audio_common.py new file mode 100644 index 00000000000..6c7d544b151 --- /dev/null +++ b/tools/audio_common.py @@ -0,0 +1,1526 @@ +#!/usr/bin/env python3 +import xml.etree.ElementTree as XmlTree +import struct +import math +from makeelf.elf import EM + +# Common Class Definitions +class StructPackSpec: + def __init__(self, archLE=False, arch64=False): + self.le = archLE + self.byte_order_char = ">" + if archLE: + self.byte_order_char = "<" + self.is_64 = arch64 + + def pointerSize(self): + if self.is_64: + return 8 + else: + return 4 + + def pointerPaddingSize(self): + if self.is_64: + return 4 + else: + return 0 + + def genPackString(self, base_string): + if self.is_64: + base_string = base_string.replace("P", "Q").replace("X", "xxxx") + else: + base_string = base_string.replace("P", "I").replace("X", "") + return self.byte_order_char + base_string + +class AifReader: + def __init__(self, filepath): + self.path = filepath + input = open(filepath, 'rb') + self.sections = {} + self.appl_sections = [] + self.total_size = 0 + self.is_aifc = False + + #Read header + assert input.read(4) == b"FORM" + self.total_size = struct.unpack(">L", input.read(4)) + assert input.read(3) == b"AIF" + typeb = input.read(1) + if typeb == b"C": + self.is_aifc = True + + #Scan chunks and map + offset = 12 + + while True: + magicno = input.read(4) + if not magicno or len(magicno) < 4: + break + secmagic = magicno.decode('utf-8') + secsize, = struct.unpack(">L", input.read(4)) + offset += 8 + if secmagic == "APPL": + self.appl_sections.append((offset, secsize)) + else: + self.sections[secmagic] = (offset, secsize) + input.seek(offset + secsize) + offset += secsize + + input.close() + + def loadData(self, offset, size): + sec_dat = None + with open(self.path, 'rb') as f: + f.seek(offset) + sec_dat = f.read(size) + return sec_dat + + def loadSectionData(self, magicno): + section_loc = self.sections[magicno] + if section_loc is None: + return None + return self.loadData(section_loc[0], section_loc[1]) + + def loadApplSectionData(self, idx): + if idx < 0 or idx >= len(self.appl_sections): + return None + section_loc = self.appl_sections[idx] + if section_loc is None: + return None + return self.loadData(section_loc[0], section_loc[1]) + +class AifcWriter: + def __init__(self, out): + self.out = out + self.sections = [] + self.total_size = 0 + + def add_section(self, tp, data): + assert isinstance(tp, bytes) + assert isinstance(data, bytes) + self.sections.append((tp, data)) + self.total_size += align(len(data), 2) + 8 + + def add_custom_section(self, tp, data): + self.add_section(b"APPL", b"stoc" + self.pstring(tp) + data) + + def pstring(self, data): + return bytes([len(data)]) + data + (b"" if len(data) % 2 else b"\0") + + def finish(self): + # total_size isn't used, and is regularly wrong. In particular, vadpcm_enc + # preserves the size of the input file... + self.total_size += 4 + self.out.write(b"FORM" + struct.pack(">I", self.total_size) + b"AIFC") + for (tp, data) in self.sections: + self.out.write(tp + struct.pack(">I", len(data))) + self.out.write(data) + if len(data) % 2: + self.out.write(b"\0") + +#Util Functions 1 +def tryStr2Num(val): + try: + return int(val) + except: + try: + return float(val) + except: + return val + +def loadSoundData(aif_path): + aif_reader = AifReader(aif_path) + snd_data = aif_reader.loadSectionData('SSND') + + if snd_data is None: + #It SHOULD be SSND, but just in case, check for a CSND + snd_data = aif_reader.loadSectionData('CSND') + + return snd_data + +def toNote(note): + tone = (note + 9) % 12 + octave = str(math.floor((((note + 9) / 12) + 1))) + + tone_str = { + 0: "C", + 1: "C♯", + 2: "D", + 3: "D♯", + 4: "E", + 5: "F", + 6: "F♯", + 7: "G", + 8: "G♯", + 9: "A", + 10: "A♯", + 11: "B" + }.get(tone) + + return "{0}{1}".format(tone_str, octave) + +def parseNoteName(noteName): + #tone_str = noteName[0] + #oct_str = noteName[1:] + #if noteName[1] == '♯': + # tone_str = noteName[0:2] + # oct_str = noteName[2:] + + #This works if oct_str is never more than one digit/char + tone_str = noteName[:-1] + oct_str = noteName[-1:] + + tone = { + 'C' : 0, + 'C♯': 1, + 'D' : 2, + 'D♯': 3, + 'E' : 4, + 'F' : 5, + 'F♯': 6, + 'G' : 7, + 'G♯': 8, + 'A' : 9, + 'A♯': 10, + 'B' : 11, + }.get(tone_str) + + #Returns the N64 note, which is MIDI - 21 + oct = int(oct_str) - 1 + return ((oct * 12) + tone) - 9 + +def toMedium(medium): + return { + 0: "RAM", + 2: "Cartridge", + 3: "Disk Drive", + "RAM": 0, + "Cartridge": 2, + "Disk Drive": 3 + }.get(medium) + +def toCachePolicy(policy): + return { + 0: "Permanent", + 1: "Persistent", + 2: "Temporary", + 3: "Any", + 4: "AnyNoSyncLoad", + "Permanent" : 0, + "Persistent" : 1, + "Temporary" : 2, + "Any" : 3, + "AnyNoSyncLoad" : 4 + }.get(policy) + +def toCodecID(codec): + return { + 0: b"ADP9", + 1: b"HPCM", + 2: b"NONE", + 3: b"ADP5", + 4: b"RVRB", + 5: b"NONE", + b"VAPC":0, + b"ADP9":0, + b"HPCM":1, + b"NONE":2, + b"ADP5":3, + b"RVRB":4, + b"NONE":5 + }.get(codec) + +def toCodecName(codec): + return { + 0: b"Nintendo ADPCM 9-byte frame format", + 1: b"Half-frame PCM", + 2: b"not compressed", + 3: b"Nintendo ADPCM 5-byte frame format", + 4: b"Nintendo Reverb format", + 5: b"not compressed" + }.get(codec) + +def parse_f80(data): + exp_bits, mantissa_bits = struct.unpack(">HQ", data) + sign_bit = exp_bits & 2 ** 15 + exp_bits ^= sign_bit + sign = -1 if sign_bit else 1 + if exp_bits == mantissa_bits == 0: + return sign * 0.0 + assert exp_bits != 0, "sample rate is a denormal" + assert exp_bits != 0x7FFF, "sample rate is infinity/nan" + mant = float(mantissa_bits) / 2 ** 63 + return sign * mant * pow(2, exp_bits - 0x3FFF) + +def serialize_f80(num): + num = float(num) + f64, = struct.unpack(">Q", struct.pack(">d", num)) + f64_sign_bit = f64 & 2 ** 63 + if num == 0.0: + if f64_sign_bit: + return b"\x80" + b"\0" * 9 + else: + return b"\0" * 10 + exponent = (f64 ^ f64_sign_bit) >> 52 + assert exponent != 0, "can't handle denormals" + assert exponent != 0x7FF, "can't handle infinity/nan" + exponent -= 1023 + f64_mantissa_bits = f64 & (2 ** 52 - 1) + f80_sign_bit = f64_sign_bit << (80 - 64) + f80_exponent = (exponent + 0x3FFF) << 64 + f80_mantissa_bits = 2 ** 63 | (f64_mantissa_bits << (63 - 52)) + f80 = f80_sign_bit | f80_exponent | f80_mantissa_bits + return struct.pack(">HQ", f80 >> 64, f80 & (2 ** 64 - 1)) + +def align(val, al): + return (val + (al - 1)) & -al + +def padding16(val): + mod16 = val & 0xF + if mod16 > 0: + return 16 - mod16 + return 0 + +def parse_machine(machine): + return { + "mips": EM.EM_MIPS, + "mips2": EM.EM_MIPS, + "mips3": EM.EM_MIPS, + "x64": EM.EM_X86_64, + "x86-64": EM.EM_X86_64, + "x86": EM.EM_386, + "386": EM.EM_386, + "arm": EM.EM_ARM + }.get(machine.lower(), "mips") + +#Audio Class Definitions +class PCMLoop: + def __init__(self): + self.start = -1 + self.end = -1 + self.count = 0 + self.predictorState = [] + self.addr = -1 + + def parseFrom(self, input, baseOffset, offset, usedFontData): + totalSize = 16 + self.start, self.end, self.count, originalLength = struct.unpack(">LLll", input[0:16]) + assert originalLength == 0 + if self.count != 0: + self.predictorState = struct.unpack(">16h", input[16:]) + totalSize += 32 + usedFontData.append((self, baseOffset + offset, baseOffset + offset + totalSize)) + return totalSize + + def serializeTo(self, output, packspecs=StructPackSpec()): + wcount = 16 + #Start and end are in sample frames, so just keep 32-bit regardless of target. + output.write(struct.pack(packspecs.genPackString("IIiI"), self.start, self.end, self.count, 0)) + if self.count != 0: + for i in range(16): + output.write(struct.pack(packspecs.genPackString("h"), self.predictorState[i])) + wcount += 2 + return wcount + + def loopsEqual(self, other): + if other is None: + return False + if not isinstance(other, PCMLoop): + return False + if self.start != other.start: + return False + if self.end != other.end: + return False + if self.count != other.count: + return False + if self.count != 0: + if self.predictorState != other.predictorState: + return False + return True + +class PCMBook: + def __init__(self): + self.order = 0 + self.predictorCount = 0 + self.predictors = [] + self.addr = -1 + + def entryCount(self): + return self.order * self.predictorCount * 8 + + def calculatePadding(self): + totalSize = 8 + (self.entryCount() * 2) + padding = 16 - (totalSize % 16) + if padding > 15: + padding = 0 + return padding + + def parseFrom(self, input, baseOffset, offset, usedData): + totalSize = 8 + self.order, self.predictorCount = struct.unpack(">LL", input[0:8]) + self.predictors = [] + predictorSize = self.order * 8 + predictorBytes = predictorSize * 2 + usedData.append( + (self, + baseOffset + offset, + baseOffset + offset + 8 + (predictorSize * self.predictorCount * 2))) + + for _ in range(self.predictorCount): + self.predictors.append(struct.unpack(f">{predictorSize}h", input[totalSize:totalSize + predictorBytes])) + totalSize += predictorBytes + + return totalSize + + def serializeTo(self, output, packspecs=StructPackSpec()): + wcount = 8 + output.write(struct.pack(packspecs.genPackString("LL"), self.order, self.predictorCount)) + predictorSize = self.order * 8 + hw_pack_str = packspecs.genPackString("h") + for i in range(self.predictorCount): + for j in range(predictorSize): + output.write(struct.pack(hw_pack_str, self.predictors[i][j])) + wcount += 2 + return wcount + + def booksEqual(self, other): + if other is None: + return False + if not isinstance(other, PCMBook): + return False + if self.predictorCount != other.predictorCount: + return False + if self.order != other.order: + return False + + predictorSize = self.order * 8 + for i in range(self.predictorCount): + for j in range(predictorSize): + if self.predictors[i][j] != other.predictors[i][j]: + return False + return True + +class SampleHeader: + def __init__(self): + self.codec = 0 + self.medium = 0 + self.bank = 0 + self.u2 = 0 + self.length = 0 + self.offsetInBank = -1 + self.loopOffset = -1 + self.bookOffset = -1 + self.loop = None + self.book = None + self.addr = -1 + self.name = '' + self.idx = -1 + + #Storage for reading aiff/aifc + self.tuning = 1.0 + self.frameCount = 0 + self.fileName = '' + + def updateReferences(self): + if self.loop is not None: + self.loopOffset = self.loop.addr + if self.book is not None: + self.bookOffset = self.book.addr + + def parseFrom(self, datafile, input, name, banks, baseOffset, offset, tuning, usedData): + modes, self.u2, self.length, self.offsetInBank, self.loopOffset, self.bookOffset = struct.unpack(">bbHLLL", input) + self.name = f"SampleHeader{offset:0>8x}" + self.offset = baseOffset + offset + self.codec = (modes >> 4) & 0xF + assert self.codec == 0 or self.codec == 3 + bankIndex = (modes & 0xC) >> 2 + self.bank = banks[bankIndex] + self.tuning = tuning + assert bankIndex == 0 or bankIndex == 1 + + assert self.length % 2 == 0 + + usedData.append((self, baseOffset + offset, baseOffset + offset + 16)) + + blockSize = 9 + + if self.codec == 3: + blockSize = 5 + + if self.length % blockSize != 0: + self.length -= self.length % blockSize + + self.loop = None + if self.loopOffset != 0: + self.loop = PCMLoop() + self.loop.parseFrom(datafile[self.loopOffset:self.loopOffset + 48], baseOffset, self.loopOffset, usedData) + + self.book = None + if self.bookOffset != 0: + self.book = PCMBook() + maxOffset = min(self.bookOffset + 400, len(datafile)) + self.book.parseFrom(datafile[self.bookOffset:maxOffset], baseOffset, self.bookOffset, usedData) + + return 16 + + def updateSize(self): + blockSize = 9 + if self.codec == 3: + blockSize = 5 + + #Okay so the frame count is calculated weird. + #To get the original data length, looks like we gotta reverse it. + self.length = (self.frameCount * blockSize) // 16 + if(self.length % 2) != 0: + self.length += 1 + + def loadInfoFromAif(self, aif_path): + aif_reader = AifReader(aif_path) + comm_data = aif_reader.loadSectionData('COMM') + + self.frameCount, = struct.unpack('>L', comm_data[2:6]) + sample_rate = parse_f80(comm_data[8:18]) + if aif_reader.is_aifc: + self.codec = toCodecID(comm_data[18:22]) + + #Default loop (non-loop) + self.loop = PCMLoop() + self.loop.start = 0 + self.loop.end = self.frameCount + self.loop.count = 0 + + #Go thru appl sections to get book and loop data + appl_count = len(aif_reader.appl_sections) + if appl_count > 0: + #Read pstr to determine what it is... + for i in range(appl_count): + appl_data = aif_reader.loadApplSectionData(i) + strlen = appl_data[4] + strdat = appl_data[5:(5+strlen)] + #appl_sec_name = strdat.decode('utf-8') + if strdat == b'VADPCMCODES': + #Code table + self.book = PCMBook() + bookpos = 18 + self.book.order, self.book.predictorCount = struct.unpack(">HH", appl_data[bookpos:bookpos+4]) + bookpos += 4 + predictorSize = self.book.order * 8 + predictorBytes = predictorSize * 2 + for i in range(self.book.predictorCount): + self.book.predictors.append(struct.unpack(">" + str(predictorSize) + "h", appl_data[bookpos:(bookpos+predictorBytes)])) + bookpos += predictorBytes + elif strdat == b'VADPCMLOOPS': + #Loop data + looppos = 20 + self.loop.start, self.loop.end, self.loop.count = struct.unpack(">LLl", appl_data[looppos:looppos+12]) + looppos += 12 + if self.loop.count != 0: + self.loop.predictorState = struct.unpack(">16h", appl_data[looppos:looppos+32]) + + #Scale sample rate + self.tuning = sample_rate/32000.0 + + self.updateSize() + + def serializeTo(self, output, packspecs=StructPackSpec()): + self.updateReferences() + modes = (self.codec & 0xF) << 4 + modes |= (self.medium & 0x3) << 2 + output.write(struct.pack(packspecs.genPackString("bbHXPPP"), modes, self.u2, self.length, self.offsetInBank, self.loopOffset, self.bookOffset)) + return 4 + (3 * packspecs.pointerSize()) + packspecs.pointerPaddingSize() + + def toXML(self, root, bankNames, sampleNames): + return XmlTree.SubElement( + root, + "Sample", + { + "Name": self.name, + "File": f"{sampleNames[self.bank][self.offsetInBank]}.aifc", + "Bank": bankNames[self.bank] + } + ) + +class Envelope: + def __init__(self): + self.name = "" + self.script = [] + self.referencedScripts = {} + self.addr = -1 + + def parseFrom(self, datafile, baseOffset, offset, usedData): + advanceOffset = offset + i = 0 + self.name = f"Env_{offset:0>8x}" + self.script = [] + self.referencedScripts = [] + + while True: + key, value = struct.unpack(">hH", datafile[advanceOffset : advanceOffset + 4]) + if key == 0 and value != 0: + break + elif key == -1 and value != 0: + break + elif key == -2: + if value == 0: + break + else: + if value < offset or value > advanceOffset + 0x20: + ref_env = Envelope() + ref_env.parseFrom(datafile, baseOffset, value, usedData) + self.referencedScripts.append(ref_env) + self.script.append(("ADSR_GOTO", value)) + elif key == -3 and value != 0: + break + elif key > 0 and value > 32767: + break + else: + cmd = key + cmd = { + 0: "ADSR_DISABLE", + -1: "ADSR_HANG", + -3: "ADSR_RESTART" + }.get(cmd, cmd) + self.script.append((cmd, value)) + if key == -1 or key == -3: + break + + advanceOffset += 4 + i += 1 + + if len(self.script) == 0: + raise Exception("Not a valid envelope script") + + usedData.append((self, baseOffset + offset, baseOffset + advanceOffset + 4)) + return advanceOffset - offset + + def serialSize(self): + return len(self.script) * 4 + + def serializeTo(self, output, packspecs=StructPackSpec()): + if len(self.script) == 0: + raise Exception("Not a valid envelope script") + mysize = 0 + i = 0 + last = False + for script_element in self.script: + cmd = script_element[0] + val = script_element[1] + + if isinstance(cmd, str): + cmd = { + "ADSR_DISABLE": 0, + "ADSR_HANG": -1, + "ADSR_GOTO": -2, + "ADSR_RESTART": -3, + }.get(cmd) + + if cmd == -2: + #Update link. + val = self.referencedScripts[i] + if isinstance(val, Envelope): + val = val.addr + if val == 0: + break + elif cmd == -1 or cmd == -3: + if val != 0: + break + last = True + elif cmd > 0 and val > 32767: + break + + output.write(struct.pack(packspecs.genPackString("hH"), cmd, val)) + + i += 1 + mysize += 4 + + if last: + break + + return mysize + + def fromXML(self, xml_element): + self.script = [] + self.referencedScripts = {} + if xml_element is None: + return + + self.name = xml_element.get("Name") + e_script = xml_element.find("Script") + if e_script is None: + return + + elist_points = e_script.findall("Point") + if elist_points is None: + return + + for e_point in elist_points: + first = e_point.get("Delay") + second = e_point.get("Value") + + #Try to convert to numbers + first = tryStr2Num(first) + second = tryStr2Num(second) + + self.script.append((first, second)) + + def toXML(self, root): + envelopeRoot = XmlTree.SubElement(root, "Envelope", { "Name": self.name }) + + script = XmlTree.SubElement(envelopeRoot, "Script") + + [XmlTree.SubElement(script, "Point", { "Delay": str(x[0]), "Value": str(x[1]) }) for x in self.script] + + return envelopeRoot + +class SoundEffect: + def __init__(self): + self.name = '' + self.enum = '' + self.pitch = 1.0 + self.sample = None + self.addr = -1 + self.idx = -1 + + self.headerOffset = -1 #Offset of sample info in font + self.sampleName = '' + + def parseFrom(self, datafile, input, effectdef, banks, baseOffset, offset, index, usedFontData): + self.idx = index + self.offset = offset + if effectdef: + self.name = effectdef.name or f"Effect_{offset:0>8x}" + self.enum = effectdef.enum + else: + self.name = f"Effect_{offset:0>8x}" + self.enum = "" + self.headerOffset, self.pitch = struct.unpack(">Lf", input) + usedFontData.append((self, baseOffset + offset, baseOffset + offset + 8)) + self.sample = SampleHeader() + self.sample.parseFrom(datafile, datafile[self.headerOffset:self.headerOffset + 16], self.name, banks, baseOffset, self.headerOffset, self.pitch, usedFontData) + + def serializeTo(self, output, packspecs=StructPackSpec()): + if self.sample is not None: + self.headerOffset = self.sample.addr + output.write(struct.pack(packspecs.genPackString("PfX"), self.headerOffset, self.pitch)) + return packspecs.pointerSize() + 4 + packspecs.pointerPaddingSize() + + def fromXML(self, xml_element): + if xml_element is None: + return + + self.name = xml_element.get("Name") + self.enum = xml_element.get("Enum") + self.sampleName = xml_element.get("Sample") + if self.sampleName is not None: + if self.sampleName.endswith(".aifc"): + self.sampleName = self.sampleName[:-5] + + pitch_str = xml_element.get("Pitch") + if pitch_str is not None: + self.pitch = float(pitch_str) + else: + self.pitch = -1.0 + + idx_str = xml_element.get("Index") + if idx_str is not None: + self.idx = int(idx_str) + + def toXML(self, root, samples, sampleNames, tunings): + element = XmlTree.SubElement(root, "SoundEffect") + + element.set("Name", self.name or f"Effect_{self.offset:0>8x}") + element.set("Index", str(self.idx)) + element.set("Enum", self.enum or "") + element.set("Sample", f"{sampleNames[self.sample.bank][self.sample.offsetInBank]}.aifc") + samples[self.sample.name] = self.sample + + if self.pitch != tunings[self.sample.bank][self.sample.offsetInBank]: + element.set("Pitch", str(self.pitch)) + + return element + +class Percussion: + def __init__(self): + self.name = '' + self.enum = '' + self.decay = 200 + self.pan = 64 + self.loaded = 0 + self.pitch = 1.0 + self.sample = None + self.envelope = None + self.addr = -1 + self.idx = -1 + + self.sampleName = '' + self.envName = '' + self.headerOffset = -1 + self.envelopeOffset = -1 + + def parseFrom(self, datafile, input, drumdef, banks, baseOffset, offset, index, usedFontData): + self.idx = index + self.offset = offset + if drumdef: + self.name = drumdef.name or f"Drum_{offset:0>8x}" + self.enum = drumdef.enum + else: + self.name = f"Drum_{offset:0>8x}" + self.enum = "" + self.decay, self.pan, self.loaded, self.headerOffset, self.pitch, self.envelopeOffset = struct.unpack(">bbBxLfL", input) + assert self.loaded == 0 + usedFontData.append((self, baseOffset + offset, baseOffset + offset + 16)) + self.sample = SampleHeader() + self.sample.parseFrom(datafile, datafile[self.headerOffset:self.headerOffset + 16], self.name, banks, baseOffset, self.headerOffset, self.pitch, usedFontData) + self.envelope = Envelope() + self.envelope.parseFrom(datafile, baseOffset, self.envelopeOffset, usedFontData) + + def serializeTo(self, output, packspecs=StructPackSpec()): + if self.sample is not None: + self.headerOffset = self.sample.addr + if self.envelope is not None: + self.envelopeOffset = self.envelope.addr + output.write(struct.pack(packspecs.genPackString("bbBxXPfXP"), self.decay, self.pan, self.loaded, self.headerOffset, self.pitch, self.envelopeOffset)) + return 8 + (2*packspecs.pointerSize()) + (2*packspecs.pointerPaddingSize()) + + def fromXML(self, xml_element): + if xml_element is None: + return + + self.name = xml_element.get("Name") + self.enum = xml_element.get("Enum") + self.envName = xml_element.get("Envelope") + self.sampleName = xml_element.get("Sample") + if self.sampleName is not None: + if self.sampleName.endswith(".aifc"): + self.sampleName = self.sampleName[:-5] + + pitch_str = xml_element.get("Pitch") + if pitch_str is not None: + self.pitch = float(pitch_str) + else: + self.pitch = -1.0 + decay_str = xml_element.get("Decay") + if decay_str is not None: + self.decay = int(decay_str) + pan_str = xml_element.get("Pan") + if pan_str is not None: + self.pan = int(pan_str) + idx_str = xml_element.get("Index") + if idx_str is not None: + self.idx = int(idx_str) + + def toXML(self, root, samples, envelopes, sampleNames, tunings): + drumElement = XmlTree.SubElement(root, "Drum") + + drumElement.set("Name", self.name or f"Drum_{self.offset:0>8x}") + drumElement.set("Index", str(self.idx)) + drumElement.set("Enum", self.enum or "") + drumElement.set("Decay", str(self.decay)) + drumElement.set("Pan", str(self.pan)) + drumElement.set("Sample", f"{sampleNames[self.sample.bank][self.sample.offsetInBank]}.aifc") + samples[self.sample.name] = self.sample + drumElement.set("Envelope", self.envelope.name) + envelopes[self.envelope.name] = self.envelope + + if self.pitch != tunings[self.sample.bank][self.sample.offsetInBank]: + drumElement.set("Pitch", str(self.pitch)) + + return drumElement + +class Instrument: + def __init__(self): + self.name = "" + self.enum = "" + self.decay = 0 + self.loaded = 0 + self.lowRange = 0 + self.highRange = 127 + self.keyLowPitch = -1.0 #Marks to match sound sample + self.keyMedPitch = -1.0 + self.keyHighPitch = -1.0 + self.keyLowSample = None + self.keyMedSample = None + self.keyHighSample = None + self.envelope = None + self.addr = -1 + self.idx = -1 + + self.keyLowOffset = -1 + self.keyMedOffset = -1 + self.keyHighOffset = -1 + self.envelopeOffset = -1 + self.keyLowName = '' + self.keyMedName = '' + self.keyHighName = '' + self.envName = '' + + def updateReferences(self): + if self.keyLowSample is not None: + self.keyLowOffset = self.keyLowSample.addr + if self.keyMedSample is not None: + self.keyMedOffset = self.keyMedSample.addr + if self.keyHighSample is not None: + self.keyHighOffset = self.keyHighSample.addr + if self.envelope is not None: + self.envelopeOffset = self.envelope.addr + + def getSamples(self): + samples = [] + if self.keyLowSample: + samples.append(self.keyLowSample) + if self.keyMedSample: + samples.append(self.keyMedSample) + if self.keyHighSample: + samples.append(self.keyHighSample) + return samples + + def parseFrom(self, datafile, input, fontname, instdef, banks, baseOffset, offset, index, usedFontData): + self.idx = index + self.offset = offset + if instdef: + self.name = instdef.name or f"Inst_{index}_{offset:0>8x}_{fontname}" + self.enum = instdef.enum + else: + self.name = f"Inst_{index}_{offset:0>8x}_{fontname}" + self.enum = "" + self.loaded, self.lowRange, self.highRange, self.decay, self.envelopeOffset, self.keyLowOffset, self.keyLowPitch, self.keyMedOffset, self.keyMedPitch, self.keyHighOffset, self.keyHighPitch = struct.unpack(">BBBbLLfLfLf", input) + assert self.loaded == 0 + usedFontData.append((self, baseOffset + offset, baseOffset + offset + 32)) + self.envelope = Envelope() + self.envelope.parseFrom(datafile, baseOffset, self.envelopeOffset, usedFontData) + self.keyLowSample = None if self.keyLowOffset == 0 else SampleHeader() + if self.keyLowSample: + self.keyLowSample.parseFrom(datafile, datafile[self.keyLowOffset:self.keyLowOffset + 16], self.name, banks, baseOffset, self.keyLowOffset, self.keyLowPitch, usedFontData) + self.keyMedSample = None if self.keyMedOffset == 0 else SampleHeader() + if self.keyMedSample: + self.keyMedSample.parseFrom(datafile, datafile[self.keyMedOffset:self.keyMedOffset + 16], self.name, banks, baseOffset, self.keyMedOffset, self.keyMedPitch, usedFontData) + self.keyHighSample = None if self.keyHighOffset == 0 else SampleHeader() + if self.keyHighSample: + self.keyHighSample.parseFrom(datafile, datafile[self.keyHighOffset:self.keyHighOffset + 16], self.name, banks, baseOffset, self.keyHighOffset, self.keyHighPitch, usedFontData) + + def serializeTo(self, output, packspecs=StructPackSpec()): + self.updateReferences() + output.write(struct.pack(packspecs.genPackString("BBBb"), self.loaded, self.lowRange, self.highRange, self.decay)) + if self.envelope is None: + output.write(struct.pack(packspecs.genPackString("X4x"))) + else: + output.write(struct.pack(packspecs.genPackString("XP"), self.envelopeOffset)) + + if self.keyLowSample is None: + output.write(struct.pack(str(packspecs.pointerSize() << 1) + "x")) + else: + output.write(struct.pack(packspecs.genPackString("PfX"), self.keyLowOffset, self.keyLowPitch)) + if self.keyMedSample is None: + output.write(struct.pack(str(packspecs.pointerSize() << 1) + "x")) + else: + output.write(struct.pack(packspecs.genPackString("PfX"), self.keyMedOffset, self.keyMedPitch)) + if self.keyHighSample is None: + output.write(struct.pack(str(packspecs.pointerSize() << 1) + "x")) + else: + output.write(struct.pack(packspecs.genPackString("PfX"), self.keyHighOffset, self.keyHighPitch)) + + return 16 + (packspecs.pointerSize() << 2) + (packspecs.pointerPaddingSize() << 2) + + def fromXML(self, xml_element): + if xml_element is None: + return + + self.name = xml_element.get("Name") + self.enum = xml_element.get("Enum") + self.envName = xml_element.get("Envelope") + + pitch_str = xml_element.get("Pitch") + if pitch_str is not None: + self.pitch = float(pitch_str) + decay_str = xml_element.get("Decay") + if decay_str is not None: + self.decay = int(decay_str) + idx_str = xml_element.get("Index") + if idx_str is not None: + self.idx = int(idx_str) + + e_key = xml_element.find("LowKey") + if e_key is not None: + self.keyLowName = e_key.get("Sample") + if self.keyLowName is not None: + if self.keyLowName.endswith(".aifc"): + self.keyLowName = self.keyLowName[:-5] + note_str = e_key.get("MaxNote") + if note_str is not None: + self.lowRange = parseNoteName(note_str) + else: + self.lowRange = 0 + pitch_str = e_key.get("Pitch") + if pitch_str is not None: + self.keyLowPitch = float(pitch_str) + else: + self.keyLowPitch = -1.0 + else: + self.lowRange = 0 + self.keyLowPitch = 0.0 + self.keyLowSample = None + self.keyLowName = '' + + e_key = xml_element.find("MediumKey") + if e_key is not None: + self.keyMedName = e_key.get("Sample") + if self.keyMedName is not None: + if self.keyMedName.endswith(".aifc"): + self.keyMedName = self.keyMedName[:-5] + pitch_str = e_key.get("Pitch") + if pitch_str is not None: + self.keyMedPitch = float(pitch_str) + else: + self.keyMedPitch = -1.0 + else: + self.keyMedPitch = 0.0 + self.keyMedSample = None + self.keyMedName = '' + + e_key = xml_element.find("HighKey") + if e_key is not None: + self.keyHighName = e_key.get("Sample") + if self.keyHighName is not None: + if self.keyHighName.endswith(".aifc"): + self.keyHighName = self.keyHighName[:-5] + note_str = e_key.get("MinNote") + if note_str is not None: + self.highRange = parseNoteName(note_str) + else: + self.highRange = 127 + pitch_str = e_key.get("Pitch") + if pitch_str is not None: + self.keyHighPitch = float(pitch_str) + else: + self.keyHighPitch = -1.0 + else: + self.highRange = 0 + self.keyHighPitch = 0.0 + self.keyHighSample = None + self.keyHighName = '' + + def toXML(self, root, samples, envelopes, sampleNames, tunings): + element = XmlTree.SubElement( + root, + "Instrument", + { + "Name": self.name or f"Inst_{self.offset:0>8x}", + "Index": str(self.idx), + "Enum": self.enum or "", + "Decay": str(self.decay), + "Envelope": self.envelope.name + } + ) + + lowKeyElement = XmlTree.SubElement(element, "LowKey") + medKeyElement = XmlTree.SubElement(element, "MediumKey") + hiKeyElement = XmlTree.SubElement(element, "HighKey") + + if self.keyLowSample is not None: + keyLow = self.keyLowSample + samples[keyLow.name] = keyLow + lowKeyElement.set("Sample", f"{sampleNames[keyLow.bank][keyLow.offsetInBank]}.aifc") + lowKeyElement.set("MaxNote", toNote(self.lowRange)) + if self.keyLowPitch != tunings[keyLow.bank][keyLow.offsetInBank]: + lowKeyElement.set("Pitch", str(self.keyLowPitch)) + if self.keyMedSample is not None: + keyMed = self.keyMedSample + samples[keyMed.name] = keyMed + medKeyElement.set("Sample", f"{sampleNames[keyMed.bank][keyMed.offsetInBank]}.aifc") + if self.keyMedPitch != tunings[keyMed.bank][keyMed.offsetInBank]: + medKeyElement.set("Pitch", str(self.keyMedPitch)) + if self.keyHighSample is not None: + keyHigh = self.keyHighSample + samples[keyHigh.name] = keyHigh + hiKeyElement.set("Sample", f"{sampleNames[keyHigh.bank][keyHigh.offsetInBank]}.aifc") + hiKeyElement.set("MinNote", toNote(self.highRange)) + if self.keyHighPitch != tunings[keyHigh.bank][keyHigh.offsetInBank]: + hiKeyElement.set("Pitch", str(self.keyHighPitch)) + + envelopes[self.envelope.name] = self.envelope + + return element + +class UnusedData: + def __init__(self, offset, data): + self.offset = offset + self.data = data + +class SampleTableEntry: + def __init__(self, name): + self.name = name + self.index = -1 + self.offset = -1 + self.length = 0 + self.medium = 2 + self.cache = 4 + + def parseFrom(self, input): + self.offset, self.length, self.medium, self.cache = struct.unpack(">LLBB6x", input) + + def serializeTo(self, output, packspecs=StructPackSpec()): + output.write(struct.pack(packspecs.genPackString("LLBB6x"), self.offset, self.length, self.medium, self.cache)) + +class SoundfontEntry: + def __init__(self): + self.offset = -1 + self.length = 0 + self.medium = 2 + self.cache = 4 + self.bank = -1 + self.bank2 = -1 + self.instrumentCount = 0 + self.percussionCount = 0 + self.effectCount = 0 + + def parseFrom(self, input): + self.offset, self.length, self.medium, self.cache, self.bank, self.bank2, self.instrumentCount, self.percussionCount, self.effectCount = struct.unpack(">LLBBbbBBH", input) + + def serializeTo(self, output, packspecs=StructPackSpec()): + output.write(struct.pack(packspecs.genPackString("LLBBbbBBH"), self.offset, self.length, self.medium, self.cache, self.bank, self.bank2, self.instrumentCount, self.percussionCount, self.effectCount)) + +class Soundfont: + def __init__(self): + self.name = '' + self.symbol = None + self.idx = -1 + self.medium = 2 + self.cachePolicy = 2 + self.offset = -1 + self.length = -1 + + self.bank1 = None + self.bank2 = None + self.bankOverride = None + self.bankNames = [] + self.bankIdx1 = -1 + self.bankIdx2 = -1 + + self.instruments = [] + self.percussion = [] + self.soundEffects = [] + self.unused = [] + self.envelopes = {} + + self.inst_read = 0 + self.perc_read = 0 + self.sfx_read = 0 + + self.instIdxLookup = {} + self.percIdxLookup = {} + self.sfxIdxLookup = {} + + #Needed only for matching (optional) + #List of samples in order appearing in font bin. + self.sampleOrder = [] #List of tuples (block name, file name (w/o ext)) + self.unusedDat = {} + self.apparent_banks = [] + self.apparent_bank = -1 + + def getAllEnvelopes(self): + elist = [] + for item in self.envelopes.items(): + elist.append(item[1]) + return elist + + def slotCount(read_val, lookup_map, block_list): + if len(lookup_map) < 1: + return read_val + keyz = sorted(lookup_map.keys(), reverse=True) + max_used = keyz[0] + 1 + empty_exp = read_val - len(block_list) + if empty_exp <= 0: + return max_used + empty_ct = 0 + for i in range(max_used): + if not i in lookup_map: + empty_ct += 1 + return max_used + (empty_exp - empty_ct) + + def instSlotCount(self): + return Soundfont.slotCount(self.inst_read, self.instIdxLookup, self.instruments) + + def percSlotCount(self): + return Soundfont.slotCount(self.perc_read, self.percIdxLookup, self.percussion) + + def sfxSlotCount(self): + return Soundfont.slotCount(self.sfx_read, self.sfxIdxLookup, self.soundEffects) + + def getSamples(self): + samples = [] + [samples.extend(instrument.getSamples()) for instrument in self.instruments if type(instrument) is not int] + [samples.append(drum.sample) for drum in self.percussion if type(drum) is not int] + [samples.append(effect.sample) for effect in self.soundEffects if type(effect) is not int] + return samples + + def parseFrom(self, entry, datafile, fontdef, usedFontData): + self.name = fontdef.name if fontdef else f"Font_{entry.offset:0>8x}" + self.symbol = fontdef.symbol + self.idx = int(fontdef.index) + self.bankOverride = int(fontdef.bankOverride) if fontdef.bankOverride else None + self.medium = entry.medium + self.cachePolicy = entry.cache + self.bankIdx1 = entry.bank + self.bankIdx2 = entry.bank2 + self.offset = entry.offset + self.length = entry.length + + banks = [int(self.bankOverride)] if self.bankOverride else [self.bankIdx1, self.bankIdx2] + + endOffset = entry.offset + 8 + percussionOffset, effectsOffset = struct.unpack(">LL", datafile[entry.offset:endOffset]) + instrumentOffsets = [] + if entry.instrumentCount != 0: + newEndOffset = endOffset + (entry.instrumentCount * 4) + instrumentOffsets = struct.unpack(f">{entry.instrumentCount}L", datafile[endOffset:newEndOffset]) + endOffset = newEndOffset + + usedFontData.append((self, entry.offset, endOffset)) + + setData = datafile[entry.offset:] + percussionTable = setData[percussionOffset:] + effectsTable = setData[effectsOffset:] + + if entry.instrumentCount > 0: + instIdx = 0 + for offset in instrumentOffsets: + instdef = None + if fontdef: + instdef = fontdef.instruments[instIdx] if instIdx < len(fontdef.instruments) else None + buffer = setData[offset:offset + 32] + instrument = instIdx if offset == 0 else Instrument() + if type(instrument) is Instrument: + instrument.parseFrom(setData, buffer, self.name, instdef, banks, entry.offset, offset, instIdx, usedFontData) + self.instruments.append(instrument) + instIdx += 1 + + if entry.effectCount > 0: + for i in range(entry.effectCount): + effectdef = None + if fontdef: + effectdef = fontdef.effects[i] if i < len(fontdef.effects) else None + buffer = effectsTable[i * 8:(i * 8) + 8] + offset = struct.unpack(">L", buffer[0:4])[0] + effect = i if offset == 0 else SoundEffect() + if type(effect) is SoundEffect: + effect.parseFrom(setData, buffer, effectdef, banks, entry.offset, effectsOffset + (i * 8), i, usedFontData) + self.soundEffects.append(effect) + + if entry.percussionCount > 0: + usedFontData.append((self, entry.offset + percussionOffset, entry.offset + percussionOffset + (entry.percussionCount * 4))) + percussionsOffsets = struct.unpack(f">{entry.percussionCount}L", percussionTable[:entry.percussionCount * 4]) + for i in range(entry.percussionCount): + drumdef = None + if fontdef: + drumdef = fontdef.drums[i] if i < len(fontdef.drums) else None + offset = percussionsOffsets[i] + percussion = i if offset == 0 else Percussion() + if type(percussion) is Percussion: + percussion.parseFrom(setData, setData[offset:offset + 16], drumdef, banks, entry.offset, offset, i, usedFontData) + self.percussion.append(percussion) + + self.instruments = sorted(self.instruments, key=lambda i: i if type(i) is int else i.offset) + self.percussion = sorted(self.percussion, key=lambda d: d if type(d) is int else d.offset) + self.soundEffects = sorted(self.soundEffects, key=lambda x: x if type(x) is int else x.offset) + + def fromXML(self, xml_element): + #Read font attr + med_str = xml_element.get("Medium") + cache_str = xml_element.get("CachePolicy") + self.symbol = xml_element.get("Symbol") + if med_str is not None: + self.medium = toMedium(med_str) + if cache_str is not None: + self.cachePolicy = toCachePolicy(cache_str) + + #Read bank names + e_banks = xml_element.find("SampleBanks") + e_list_bank = e_banks.findall("Bank") + + for e_bank in e_list_bank: + self.bankNames.append(e_bank.get("Name")) + + #See if there's a funky bank override + e_banks = xml_element.find("ForceSampleBank") + if e_banks: + self.apparent_banks = self.bankNames + self.bankNames = [] + e_list_bank = e_banks.findall("Bank") + for e_bank in e_list_bank: + self.bankNames.append(e_bank.get("Name")) + + #Read envelopes + e_envelopes = xml_element.find("Envelopes") + if e_envelopes is not None: + e_env_list = e_envelopes.findall("Envelope") + for e_env in e_env_list: + env = Envelope() + env.fromXML(e_env) + self.envelopes[env.name] = env + + #resolve env references + env_list = self.getAllEnvelopes() + for env in env_list: + for script in env.script: + cmd = script[0] + if cmd == "ADSR_GOTO" or cmd == -2: + val = script[1] + if val is not None: + refscript = self.envelopes[val] + env.referencedScripts[val] = refscript + + #Read SFX + use_idx_field = True + e_soundeffects = xml_element.find("SoundEffects") + if e_soundeffects is not None: + e_sfx_list = e_soundeffects.findall("SoundEffect") + if e_sfx_list is not None: + for e_sfx in e_sfx_list: + self.sfx_read += 1 + sfx = SoundEffect() + sfx.fromXML(e_sfx) + if sfx.sampleName is not None: + self.soundEffects.append(sfx) + if (not use_idx_field) or (sfx.idx < 0): + #If indices are missed once, they are hereby ignored (for now) + use_idx_field = False + sfx.idx = self.sfx_read - 1 + self.sfxIdxLookup[sfx.idx] = sfx + + #Read Percussion + use_idx_field = True + e_drums = xml_element.find("Drums") + if e_drums is not None: + e_drum_list = e_drums.findall("Drum") + if e_drum_list is not None: + for e_drum in e_drum_list: + self.perc_read += 1 + drum = Percussion() + drum.fromXML(e_drum) + if drum.sampleName is not None: + self.percussion.append(drum) + #Find envelope + if drum.envName: + drum.envelope = self.envelopes[drum.envName] + if (not use_idx_field) or (drum.idx < 0): + #If indices are missed once, they are hereby ignored (for now) + use_idx_field = False + drum.idx = self.perc_read - 1 + self.percIdxLookup[drum.idx] = drum + + #Read Instruments + use_idx_field = True + e_insts = xml_element.find("Instruments") + if e_insts is not None: + e_inst_list = e_insts.findall("Instrument") + if e_inst_list is not None: + for e_inst in e_inst_list: + self.inst_read += 1 + inst = Instrument() + inst.fromXML(e_inst) + if inst.keyMedName: + self.instruments.append(inst) + #Find envelope + if inst.envName: + inst.envelope = self.envelopes[inst.envName] + if (not use_idx_field) or (inst.idx < 0): + #If indices are missed once, they are hereby ignored (for now) + use_idx_field = False + inst.idx = self.inst_read - 1 + self.instIdxLookup[inst.idx] = inst + + #Read samples (if present) + e_samps = xml_element.find("Samples") + if e_samps is not None: + e_samp_list = e_samps.findall("Sample") + for e_samp in e_samp_list: + sname = e_samp.get("Name") + sfile = e_samp.get("File") + if sfile.endswith(".aifc"): + sfile = sfile[:-5] + self.sampleOrder.append((sname,sfile)) + + #Unused block (if present) + e_unused = xml_element.find("Unused") + if e_unused is not None: + e_data_list = e_unused.findall("Data") + if e_data_list: + for e_data in e_data_list: + data_offset = int(e_data.get("Offset")) + data_text = e_data.text + text_split = data_text.split(',') + data_list = [] + for b in text_split: + data_list.append(int(b, 16)) + self.unusedDat[data_offset] = data_list + + def toXML(self, bankNames, sampleNames, tunings): + samplesFound = {} + envelopesFound = {} + + root = XmlTree.Element("Soundfont", { + "Medium": toMedium(self.medium), + "CachePolicy": toCachePolicy(self.cachePolicy) + }) + + if (self.symbol): + root.attrib["Symbol"] = self.symbol + + banks = XmlTree.SubElement(root, "SampleBanks") + XmlTree.SubElement(banks, "Bank", { "Name": bankNames[self.bankIdx1] }) + + if self.bank2 and self.bank2 > -1: + XmlTree.SubElement(banks, "Bank", { "Name": bankNames[self.bankIdx2] }) + + if self.bankOverride: + overrideBanks = XmlTree.SubElement(root, "ForceSampleBank") + XmlTree.SubElement(overrideBanks, "Bank", { "Name": bankNames[self.bankOverride] }) + + instElements = XmlTree.SubElement(root, "Instruments") + drumElements = XmlTree.SubElement(root, "Drums") + effectElements = XmlTree.SubElement(root, "SoundEffects") + envelopes = XmlTree.SubElement(root, "Envelopes") + samples = XmlTree.SubElement(root, "Samples") + unused = None + + nullInst = set([i for i in self.instruments if type(i) is int]) + nullDrum = set([d for d in self.percussion if type(d) is int]) + nullSfx = set([x for x in self.soundEffects if type(x) is int]) + + realInst = [i for i in self.instruments if type(i) is Instrument] + realDrum = [d for d in self.percussion if type(d) is Percussion] + realSfx = [x for x in self.soundEffects if type(x) is SoundEffect] + + instruments = list(realInst) + drums = list(realDrum) + effects = list(realSfx) + + for i in nullInst: + instruments.insert(i, None) if i < len(instruments) else instruments.append(None) + for i in nullDrum: + drums.insert(i, None) if i < len(drums) else drums.append(None) + for i in nullSfx: + effects.insert(i, None) if i < len(effects) else effects.append(None) + + [inst.toXML(instElements, samplesFound, envelopesFound, sampleNames, tunings) if inst is not None else XmlTree.SubElement(instElements, "Instrument") for inst in instruments] + [drum.toXML(drumElements, samplesFound, envelopesFound, sampleNames, tunings) if drum is not None else XmlTree.SubElement(drumElements, "Drum") for drum in drums] + [effect.toXML(effectElements, samplesFound, sampleNames, tunings) if effect is not None else XmlTree.SubElement(effectElements, "SoundEffect") for effect in effects] + + for item in self.unused: + if isinstance(item, Envelope): + envelopesFound[item.name] = item + elif isinstance(item, UnusedData): + if unused == None: + unused = XmlTree.SubElement(root, "Unused") + unusedItem = XmlTree.SubElement(unused, "Data", { "Offset": str(item.offset) }) + bytes_to_str = ','.join([f"0x{x:0>x}" for x in item.data]) + unusedItem.text = bytes_to_str + for name in envelopesFound: + for referencedEnvelope in envelopesFound[name].referencedScripts: + envelopesFound[referencedEnvelope.name] = referencedEnvelope + + envelopesFound = dict(sorted(envelopesFound.items())) + samplesFound: dict[str, SampleHeader] = dict(sorted(samplesFound.items())) + + [envelope.toXML(envelopes) for _, envelope in envelopesFound.items()] + [sample.toXML(samples, bankNames, sampleNames) for _, sample in samplesFound.items()] + + return root + + def getTableEntry(self): + myentry = SoundfontEntry() + + myentry.bank = self.bankIdx1 + myentry.bank2 = self.bankIdx2 + myentry.medium = self.medium + myentry.cache = self.cachePolicy + + myentry.instrumentCount = self.instSlotCount() + myentry.percussionCount = self.percSlotCount() + myentry.effectCount = self.sfxSlotCount() + + return myentry + +class Soundbank: + def __init__(self): + self.samplesByName = {} + self.samples = [] + self.name = "" + self.idx = -1 + self.medium = 2 + self.cachePolicy = 4 + + def calculateSize(self): + mysize = 0 + for sample in self.samples: + mysize += sample.length + mysize = align(mysize, 16) + return mysize + + def getSample(self, name): + if name in self.samplesByName: + return self.samplesByName[name] + else: + return None + + def fromXML(self, xml_element): + #Read attr + med_str = xml_element.get("Medium") + cache_str = xml_element.get("CachePolicy") + if med_str is not None: + self.medium = toMedium(med_str) + if cache_str is not None: + self.cachePolicy = toCachePolicy(cache_str) + +#Common Functions +def loadBankDefTable(filepath): + bankdeftbl = [] + with open(filepath,'rb') as f: + bankcount, = struct.unpack(">H", f.read(2)) + f.read(14) + for i in range(bankcount): + record = SampleTableEntry('audiotable_' + str(i)) + record.parseFrom(f.read(16)) + bankdeftbl.append(record) + return bankdeftbl + +def loadFontDefTable(filepath): + fontdeftbl = [] + with open(filepath,'rb') as f: + fontcount, = struct.unpack(">H", f.read(2)) + f.read(14) + for i in range(fontcount): + record = SoundfontEntry() + record.parseFrom(f.read(16)) + fontdeftbl.append(record) + return fontdeftbl + +def write_soundfont_define(font, fontcount, filename): + width = int(math.log10(fontcount)) + 1 + index = str(font.idx).zfill(width) + + with open(filename, "w") as file: + file.write("# Soundfont file constants\n") + file.write(f"# ID: {font.idx}\n") + file.write(f"# Name: {font.name}\n") + file.write("\n##### INSTRUMENTS #####\n") + + for instrument in font.instruments: + if type(instrument) is int: + continue + + file.write(f".define FONT{index}_INSTR_{instrument.enum} {instrument.idx}\n") + + file.write("\n##### DRUMS #####\n") + for drum in font.percussion: + if type(drum) is int: + continue + + file.write(f".define FONT{index}_DRUM_{drum.enum} {drum.idx}\n") + + file.write("\n##### EFFECTS #####\n") + for effect in font.soundEffects: + if type(effect) is int: + continue + + file.write(f".define FONT{index}_EFFECT_{effect.enum} {effect.idx}\n") diff --git a/tools/disassemble_sequence.py b/tools/disassemble_sequence.py new file mode 100644 index 00000000000..fbf1a0f8578 --- /dev/null +++ b/tools/disassemble_sequence.py @@ -0,0 +1,792 @@ +#!/usr/bin/env python3 +from argparse import ArgumentParser +import argparse +import sys +import re +import os + +def join(*args): + ret = {} + for arg in args: + ret.update(arg) + return ret + +def get_symbols(header_file): + inst_syms = {} + drum_syms = {} + effect_syms = {} + + current_mode = "" + for line in header_file.readlines(): + if current_mode == "" and " INSTRUMENTS " in line: + current_mode = "instrument" + continue + elif current_mode == "instrument" and " DRUMS " in line: + current_mode = "drum" + continue + elif current_mode == "drum" and " EFFECTS " in line: + current_mode = "effect" + continue + + if ".define" in line and current_mode != "": + sym, index = re.match(r"\.define ([A-Z_0-9]+)\s+(\d+)", line).groups() + if current_mode == "instrument": + inst_syms[int(index)] = sym + elif current_mode == "drum": + drum_syms[int(index)] = sym + elif current_mode == "effect": + effect_syms[int(index)] = sym + + return (inst_syms, drum_syms, effect_syms) + +def get_sequence_symbols(seq_inc): + pitches = {} + fonts = {} + + for line in seq_inc.readlines(): + if "PITCH" in line: + sym, id = re.match(r"\.define ([A-Z_0-9]+)\s+(\d+)", line).groups() + pitches[int(id)] = sym + if "SOUNDFONT" in line: + sym, id = re.match(r"\.define ([A-Z_0-9]+)\s+(\d+)", line).groups() + fonts[int(id)] = sym + + return (pitches, fonts) + +control_flow_commands = { + 0xFF: ['end'], + 0xFE: ['delay1'], + 0xFD: ['delay', 'var'], + 0xFC: ['call', 'addr'], + 0xFB: ['jump', 'addr'], + 0xFA: ['beqz', 'addr'], + 0xF9: ['bltz', 'addr'], + 0xF8: ['loop', 'u8'], + 0xF7: ['loopend'], + 0xF6: ['break'], + 0xF5: ['bgez', 'addr'], + 0xF4: ['rjump', 'reladdr8'], + 0xF3: ['rbeqz', 'reladdr8'], + 0xF2: ['rbltz', 'reladdr8'], +} + +commands = {} +commands['seq'] = join(control_flow_commands, { + # non-arg commands + 0xF1: ['allocnotelist', 'u8'], + 0xF0: ['freenotelist'], + 0xDF: ['transpose', 's8'], + 0xDE: ['rtranspose', 's8'], + 0xDD: ['tempo', 'u8'], + 0xDC: ['tempochg', 's8'], + 0xDB: ['vol', 'u8'], + 0xDA: ['volmode', 's8'], + 0xD7: ['initchan', 'hex16'], + 0xD6: ['freechan', 'hex16'], + 0xD5: ['mutescale', 's8'], + 0xD4: ['mute'], + 0xD3: ['mutebhv', 'hex8'], + 0xD2: ['ldshortvelarr', 'addr'], + 0xD1: ['ldshortgatearr', 'addr'], + 0xD0: ['notealloc', 'u8'], + 0xCE: ['rand', 'u8'], + 0xCD: ['dyncall', 'addr'], + 0xCC: ['ldi', 'u8'], + 0xC9: ['and', 'u8'], + 0xC8: ['sub', 'u8'], + 0xC7: ['stseq', 'u8', 'addr'], + 0xC6: ['stop'], + 0xC5: ['scriptctr', 'u16'], + 0xC4: ['runseq', 'u8', 'u8'], + # arg commands + 0x00: ['testchan', 'bits:4'], + 0x40: ['stopchan', 'bits:4'], + 0x50: ['subio', 'bits:4'], + 0x60: ['ldres', 'bits:4', 'u8', 'u8'], + 0x70: ['stio', 'bits:4'], + 0x80: ['ldio', 'bits:4'], + 0x90: ['ldchan', 'bits:4', 'addr'], + 0xA0: ['rldchan', 'bits:4', 'reladdr16'], + 0xB0: ['ldseq', 'bits:4', 'u8', 'addr'], +}) + +commands['chan'] = join(control_flow_commands, { + # non-arg commands + 0xF1: ['allocnotelist', 'u8'], + 0xF0: ['freenotelist'], + 0xEE: ['bendfine', 's8'], + 0xED: ['gain', 'u8'], + 0xEB: ['fontinstr'], + 0xEA: ['stop'], + 0xE9: ['notepri', 'u8'], + 0xE8: ['params', 'u8', 'u8', 'u8', 's8', 's8', 'u8', 'u8', 'u8'], + 0xE7: ['ldparams', 'addr'], + 0xE6: ['samplbook', 'addr'], + 0xE5: ['rvrbidx', 'u8'], + 0xE4: ['dyncall'], + 0xE3: ['vibdelay', 'u8'], + 0xE2: ['vibdepthgrad', 'u8', 'u8', 'u8'], + 0xE1: ['vibfreqgrad', 'u8', 'u8', 'u8'], + 0xE0: ['volexp', 'u8'], + 0xDF: ['vol', 'u8'], + 0xDE: ['freqscale', 'u16'], + 0xDD: ['pan', 'u8'], + 0xDC: ['panweight', 'u8'], + 0xDB: ['transpose', 's8'], + 0xDA: ['env', 'addr'], + 0xD9: ['releaserate', 'u8'], + 0xD8: ['vibdepth', 'u8'], + 0xD7: ['vibfreq', 'u8'], +# 0xD6: ['setupdatesperframe_unimplemented', 'u8'], + 0xD4: ['reverb', 'u8'], + 0xD3: ['bend', 's8'], + 0xD2: ['sustain', 'u8'], + 0xD1: ['notealloc', 'u8'], + 0xD0: ['effects', 'u8'], + 0xCF: ['stptrtoseq', 'addr'], + 0xCE: ['ldptr', 'hex16'], + 0xCD: ['stopchan', 'u8'], + 0xCC: ['ldi', 'u8'], + 0xCB: ['ldseq', 'addr'], + 0xCA: ['mutebhv', 'hex8'], + 0xC9: ['and', 'u8'], + 0xC8: ['sub', 'u8'], + 0xC7: ['stseq', 'u8', 'addr'], + 0xC6: ['font', 'u8'], + 0xC5: ['dyntbllookup'], + 0xC4: ['noshort'], + 0xC3: ['short'], + 0xC2: ['dyntbl', 'addr'], + 0xC1: ['instr', 'u8'], + 0xBD: ['randptr', 'u16', 'u16'], + 0xBC: ['ptradd', 'u16'], + 0xBB: ['unkbb', 'u8', 'u16'], + 0xBA: ['randgate', 'u8'], + 0xB9: ['randvel', 'u8'], + 0xB8: ['rand', 'u8'], + 0xB7: ['randtoptr', 'u16'], + 0xB6: ['dyntblv'], + 0xB5: ['dyntbltoptr'], + 0xB4: ['ptrtodyntbl'], + 0xB3: ['filter', 'u8'], + 0xB2: ['ldseqtoptr', 'addr'], + 0xB1: ['freefilter'], + 0xB0: ['ldfilter', 'addr'], + # arg commands + 0x00: ['cdelay', 'bits:4'], + 0x10: ['sample', 'bits:3', 'addr'], + 0x18: ['sampleptr', 'bits:3', 'addr'], + 0x20: ['ldchan', 'bits:4', 'addr'], + 0x30: ['stcio', 'bits:4', 'u8'], + 0x40: ['ldcio', 'bits:4', 'u8'], + 0x50: ['subio', 'bits:4'], + 0x60: ['ldio', 'bits:4'], + 0x70: ['stio', 'bits:3'], + 0x78: ['rldlayer', 'bits:3', 'reladdr16'], + 0x80: ['testlayer', 'bits:3'], + 0x88: ['ldlayer', 'bits:3', 'addr'], + 0x90: ['dellayer', 'bits:3'], + 0x98: ['dynldlayer', 'bits:3'], +}) + +commands_layer_base = join(control_flow_commands, { + # non-arg commands + 0xC0: ['ldelay', 'var'], + 0xC1: ['shortvel', 'u8'], + 0xC2: ['transpose', 's8'], + 0xC3: ['shortdelay', 'var'], + 0xC4: ['legato'], + 0xC5: ['nolegato'], + 0xC6: ['instr', 'u8'], + 0xC7: ['portamento', 'hex8', 'u8', 'u8'], + 0xC8: ['noportamento'], + 0xC9: ['shortgate', 'u8'], + 0xCA: ['notepan', 'u8'], + 0xCB: ['env', 'addr', 'u8'], + 0xCC: ['nodrumpan'], + 0xCD: ['stereo', 'u8'], + 0xCE: ['bendfine', 's8'], + 0xCF: ['releaserate', 'u8'], + # arg commands + 0xD0: ['ldshortvel', 'bits:4'], + 0xE0: ['ldshortgate', 'bits:4'], +}) +del commands_layer_base[0xFD] + +commands['layer_large'] = join(commands_layer_base, { + 0x00: ['notedvg', 'bits:6', 'var', 'u8', 'u8'], + 0x40: ['notedv', 'bits:6', 'var', 'u8'], + 0x80: ['notevg', 'bits:6', 'u8', 'u8'], +}) + +commands['layer_small'] = join(commands_layer_base, { + 0x00: ['shortdvg', 'bits:6', 'var'], + 0x40: ['shortdv', 'bits:6'], + 0x80: ['shortvg', 'bits:6'], +}) + +branches = ['jump', 'beqz', 'bltz', 'bgez', 'rjump', 'rbeqz', 'rbltz'] + +def valid_cmd_for_nbits(cmd_list, nbits): + for arg in cmd_list: + if arg.startswith('bits:'): + return int(arg.split(':')[1]) == nbits + return nbits == 0 + +parser = ArgumentParser(add_help=False) +parser.add_argument("filename", metavar="input.aseq", type=argparse.FileType("rb"), help="Input binary sequence to convert to a text sequence.") +parser.add_argument("header", metavar="soundfont.inc", type=argparse.FileType("r"), help="Soundfont include file defining instruments and drums symbols.") +parser.add_argument("sequence", metavar="sequence.inc", type=argparse.FileType("r"), help="sequence.inc file containing global defines") +parser.add_argument("--print-end-padding", action="store_true", help="Adds padding bytes to the end of the sequence.") +parser.add_argument("--cache-policy", nargs=1, required=False, default=["2"], help="Specifies the cache policy for this sequence.") +args = parser.parse_args() + +print_end_padding = args.print_end_padding +filename = args.filename +header = args.header +sequence = args.sequence +cachePolicy = args.cache_policy[0] + +try: + # should maybe renumber in hex? + seq_num = int(filename.name.split('/')[-1].split(' ')[0], 10) +except Exception: + seq_num = -1 + +try: + data = filename.read() +except Exception: + print(f"Error: could not open file {filename.name} for reading.", file=sys.stderr) + sys.exit(1) + +try: + inst_syms, drum_syms, effect_syms = get_symbols(header) +except Exception as e: + print(f"Error: could not read symbols from {header.name}.", file=sys.stderr) + sys.exit(1) + +try: + pitches, soundfonts = get_sequence_symbols(sequence) +except Exception as e: + print(f"Error: could not read symbols from {sequence.name}.", file=sys.stderr) + sys.exit(1) + +output = [None] * len(data) +alignment = [None] * len(data) +output_instate = [None] * len(data) +label_name = [None] * len(data) +label_kind = [None] * len(data) +script_start = [False] * len(data) +hit_eof = False +errors = [] +seq_writes = [] + +# Our analysis of large notes mode doesn't persist through multiple channel activations +# For simplicity, we force large notes always instead, which is valid for oot. +force_large_notes = True + +def gen_label(ind, tp): + nice_tp = tp.replace('_small', '').replace('_large', '').replace('lazy', '') + addr = hex(ind)[2:].upper() + ret = f"{nice_tp}_{addr}" + if ind >= len(data): + errors.append(f"reference to oob label {ret}") + return ret + + if label_name[ind] is not None: + return label_name[ind] + label_name[ind] = ret + label_kind[ind] = { + "seq": "sequence", + "chan": "channel", + "chan_fn": "channel", + "layer_large_fn": "layer" + }.get(tp, tp) + return ret + +def gen_mnemonic(tp, b): + mn = commands[tp][b][0] + if not mn: + mn = f"{b:02X}" + return f"{mn}" + +decode_list = [] + +def decode_one(state): + pos, tp, nesting, large, current_channel = state + orig_pos = pos + + if pos >= len(data): + global hit_eof + hit_eof = True + return + + if seq_num == 0 and pos in (0x6197, 0x6197, 0x6197): + # unfinished code + return + + if output[pos] is not None: + if output_instate[pos][:-1] != state[:-1]: + errors.append(f"got to {gen_label(orig_pos, tp)} with both state {state} and {output_instate[pos]}") + return + + def u8(): + nonlocal pos + global hit_eof + if pos == len(data): + hit_eof = True + return 0 + ret = data[pos] + pos += 1 + return ret + + def s8(): + ret = u8() + return ret - 0x100 if ret >= 0x80 else ret + + def u16(): + hi = u8() + lo = u8() + return (hi << 8) | lo + + def s16(): + ret = u16() + return ret - 0x10000 if ret >= 0x8000 else ret + + def peek16(): + nonlocal pos + ret = u16() + pos -= 2 + return ret + + def var(): + ret = u8() + if ret & 0x80: + ret = (ret << 8) & 0x7F00; + ret |= u8() + return (ret, ret < 0x80) + return (ret, False) + + if tp.endswith('entry'): + subtp = tp[:-5] + if subtp == 'layer': + subtp = 'layer_large' + addr = u16() + if subtp != 'lazyseq' and subtp != 'writeseq': + decode_list.append((addr, subtp, 0, True, current_channel)) + for p in range(orig_pos, pos): + output[p] = '' + output_instate[p] = state + if subtp == 'writeseq': + output[orig_pos] = 'entry ' + seq_writes.append((orig_pos, addr)) + else: + output[orig_pos] = 'entry ' + gen_label(addr, subtp) + if addr < len(data): + script_start[addr] = True + return + + if tp == 'envelope': + a = u16() + b = u16() + for p in range(orig_pos, pos): + output[p] = '' + output_instate[p] = state + if a >= 2**16 - 3: + a -= 2**16 + if a <= 0: + mn = ['disable', 'hang', 'goto', 'restart'][-a] + output[orig_pos] = mn + (f' {b}' if mn == 'goto' else '') + # assume any goto is backwards and stop decoding + else: + output[orig_pos] = f'point {a}, {b}' + decode_list.append((pos, tp, nesting, large, current_channel)) + return + + if tp == 'filter': + filt_str = ", ".join(str(s16()) for _ in range(8)) + for p in range(orig_pos, pos): + output[p] = '' + output_instate[p] = state + output[orig_pos] = f'filter {filt_str}' + return + + ins_byte = u8() + + cmds = commands[tp] + nbits = 0 + used_b = ins_byte + while True: + if used_b in cmds and valid_cmd_for_nbits(cmds[used_b], nbits): + break + used_b &= ~(1 << nbits) + nbits += 1 + if nbits == 8: + errors.append(f"unrecognized instruction {hex(ins_byte)} for type {tp} at label {gen_label(orig_pos, tp)}") + return + + out_mn = gen_mnemonic(tp, used_b) + out_args = [] + cmd_mn = cmds[used_b][0] + cmd_args = cmds[used_b][1:] + long_var = False + + for a in cmd_args: + if cmd_mn == 'portamento' and len(out_args) == 2 and (int(out_args[0], 0) & 0x80) == 0: + a = 'var' + if cmd_mn == 'ldptr' and seq_num == 0 and peek16() not in (0, 0x7FBC): + a = 'addr' + out_mn = "ldptr" + + if a.startswith('bits:'): + low_bits = ins_byte & ((1 << nbits) - 1) + if not (a.endswith(':ign') and low_bits == 0): + arg = str(low_bits) + if cmd_mn in ['notedvg', 'notedv', 'notevg', 'shortdvg', 'shortdv', 'shortvg']: + arg = pitches[low_bits] + out_args.append(arg) + elif a == 'u8' and cmd_mn == 'instr': + instr_num = u8() + if instr_num == 127: + instr = "FONTANY_INSTR_DRUM" + elif instr_num == 126: + instr = "FONTANY_INSTR_SFX" + else: + instr = inst_syms[instr_num] + out_args.append(instr) + elif a == 'u8': + out_args.append(str(u8())) + elif a == 'hex8': + out_args.append(hex(u8()).upper()) + elif a == 's8': + v = u8() + out_args.append(str(v if v < 128 else v - 256)) + elif a == 'u16': + out_args.append(str(u16())) + elif a == 'hex16': + out_args.append(hex(u16()).upper()) + elif a == 'var': + val, bad = var() + out_args.append(hex(val).upper()) + if bad: + long_var = True + elif a in ('addr', 'reladdr8', 'reladdr16'): + if a == 'addr': + v = u16() + elif a == 'reladdr8': + v = s8() + v += pos + else: + v = s16() + v += pos + + kind = 'addr' + if cmd_mn == 'call': + kind = tp + '_fn' + elif cmd_mn in branches: + kind = tp + elif cmd_mn in ('ldchan', 'rldchan'): + kind = 'chan' + elif cmd_mn in ('ldlayer', 'rldlayer'): + kind = 'layer' + elif cmd_mn in ('dyntbl', 'dyncall'): + kind = 'table' + elif cmd_mn == 'env': + kind = 'envelope' + elif cmd_mn == 'ldfilter': + kind = 'filter' + + if v >= len(data): + label = gen_label(v, kind) + out_args.append(label) + errors.append(f"reference to oob label {label}") + elif cmd_mn in ('stseq', 'stptrtoseq'): + out_args.append('') + seq_writes.append((orig_pos, v)) + else: + out_args.append(gen_label(v, kind)) + if cmd_mn == 'call': + decode_list.append((v, tp, 0, large, current_channel)) + script_start[v] = True + elif cmd_mn in branches: + decode_list.append((v, tp, nesting, large, current_channel)) + elif kind == 'chan': + decode_list.append((v, 'chan', 0, force_large_notes, out_args[0])) + script_start[v] = True + elif kind == 'layer': + if large: + decode_list.append((v, 'layer_large', 0, True, current_channel)) + else: + decode_list.append((v, 'layer_small', 0, True, current_channel)) + script_start[v] = True + elif kind == 'envelope': + decode_list.append((v, 'envelope', 0, True, current_channel)) + script_start[v] = True + elif kind == 'filter': + decode_list.append((v, 'filter', 0, True, current_channel)) + script_start[v] = True + else: + script_start[v] = True + else: + raise Exception(f"bad arg kind {a}") + + out_all = out_mn +# if long_var: +# out_all += "_long" + if out_args: + out_all += ' ' + out_all += ', '.join(out_args) + for p in range(orig_pos, pos): + output[p] = '' + output_instate[p] = state + output[orig_pos] = out_all + + if cmd_mn in ['hang', 'jump', 'rjump']: + return + if cmd_mn in ['loop']: + nesting += 1 + if cmd_mn == 'end': + nesting -= 1 + if cmd_mn in ['break', 'loopend']: + nesting -= 1 + if nesting < 0: + # This is iffy, and actually happens in sequence 0. It will make us + # return to the caller's caller at function end. + nesting = 0 + if cmd_mn == 'noshort': + large = True + if cmd_mn == 'short': + large = False + if nesting >= 0: + decode_list.append((pos, tp, nesting, large, current_channel)) + +def decode_rec(state, initial): + if not initial: + v = state[0] + gen_label(v, state[1]) + script_start[v] = True + decode_list.append(state) + while decode_list: + decode_one(decode_list.pop()) + +def main(): + decode_rec((0, 'seq', 0, False, None), initial=True) + + tables = [] + unused = [] + + if seq_num == 0: + tables = [ + ('chan', 0xE1, 0xE1), + ('chan', 0x1E1, 0x1E1), + ('chan', 0xEE3, 0xEE3), + ('chan', 0x16D5, 0x16D5), + ('chan', 0x17D5, 0x17D5), + ('chan', 0x315E, 0x315E), + ('chan', 0x325E, 0x325E), + ('chan', 0x335E, 0x335E), + ('chan', 0x345E, 0x345E), + ('chan', 0x5729, 0x5729), + ('chan', 0x5EE5, 0x5EE5), + ('chan', 0x5FF2, 0x5FF2), + ] + + unused = [ + (0x4BE, 'layer_large'), + (0x6F6, 'layer_large'), + (0x72C, 'layer_large'), + (0x839, 'chan'), + (0x109A, 'layer_large'), + (0x1C7A, 'envelope'), + (0x1C86, 'envelope'), + (0x1C92, 'envelope'), + (0x205E, 'layer_large'), + (0x2128, 'layer_large'), + (0x213D, 'layer_large'), + (0x3791, 'chan'), + (0x482F, 'chan'), + (0x599F, 'chan'), + (0x59B9, 'layer_large'), + (0x5B45, 'layer_large'), + (0x6185, 'chan'), + (0x61AB, 'chan'), + (0x6360, 'chan'), + (0x672C, 'envelope'), + (0x685C, 'envelope'), + (0x689C, 'envelope'), + (0x691C, 'envelope'), + (0x693C, 'envelope'), + (0x69EC, 'envelope'), + (0x6A6C, 'envelope'), + ] + + elif seq_num == 1: + tables = [ + ('layer', 0x192, 20), + ('layer', 0x1BA, 20), + ('layer', 0x1E2, 20), + ('layer', 0x20A, 20), + ('writeseq', 0x232, 20), + ('writeseq', 0x25A, 20), + ('writeseq', 0x282, 20), + ] + + elif seq_num == 2: + tables = [ + ('lazyseq', 0xC0, 2), + ('seq', 0xBC, 2), + ] + + elif seq_num == 109: + tables = [ + ('chan', 0x646, 16), + ] + unused = [ + (0x3F7, 'layer_large'), + (0x578, 'layer_large'), + (0x666, 'envelope'), + (0x66E, 'envelope'), + (0x67E, 'envelope'), + (0x6A6, 'envelope'), + (0x6BA, 'envelope'), + (0x6E2, 'envelope'), + (0x70A, 'envelope'), + (0x736, 'envelope'), + (0x74E, 'envelope'), + (0x766, 'envelope'), + (0x776, 'envelope'), + (0x782, 'envelope'), + (0x79A, 'envelope'), + (0x7A6, 'envelope'), + (0x7AE, 'envelope'), + (0x7B6, 'envelope'), + (0x7C2, 'envelope'), + (0x7D6, 'envelope'), + (0x7E6, 'envelope'), + (0x80E, 'envelope'), + (0x82A, 'envelope'), + (0x83A, 'envelope'), + (0x852, 'envelope'), + (0x862, 'envelope'), + (0x896, 'envelope'), + (0x8AE, 'envelope'), + (0x8BA, 'envelope'), + ] + + for (tp, addr, count) in tables: + for i in range(count): + decode_rec((addr + 2*i, tp + 'entry', 0, False), initial=True) + + for (addr, tp) in unused: + gen_label(addr, tp + '_unused') + decode_rec((addr, tp, 0, force_large_notes), initial=False) + + for (pos, write_to) in seq_writes: + assert '' in output[pos] + delta = 0 + while output[write_to] == '': + write_to -= 1 + delta += 1 +# if write_to > pos and all(output[i] == '' for i in range(pos+1, write_to)): +# nice_target = str(delta) +# output[pos] = output[pos].replace('writeseq', 'writeseq_nextinstr') +# else: + tp = output_instate[write_to][1] if output_instate[write_to] is not None else 'addr' + nice_target = gen_label(write_to, tp) + if delta: + nice_target += "+" + str(delta) + output[pos] = output[pos].replace('', nice_target) + + # Add unreachable 'end' markers + for i in range(1, len(data)): + if (data[i] == 0xFF and output[i] is None and output[i - 1] is not None + and label_name[i] is None): + tp = output_instate[i - 1][1] + if tp in ["seq", "chan", "layer_small", "layer_large"]: + output[i] = gen_mnemonic(tp, 0xFF) + + # Add aligners and strip padding + for i in range(len(data)): + if not output[i]: + continue + tp = output_instate[i][1] if output_instate[i] else '' + if tp == 'filter': + align = 16 + elif tp == 'envelope': + align = 2 + else: + continue + if i % align != 0: + errors.append(f"{label_name[i]} ({hex(i)}) is unaligned") + continue + alignment[i] = align + for j in range(1, align): + k = i - j + if k < 0 or output[k] is not None or data[k] != 0 or label_name[k]: + break + output[k] = "" + + # Add 'unused' marker labels + for i in range(1, len(data)): + if (output[i] is None and output[i - 1] is not None and label_name[i] is None): + script_start[i] = True + gen_label(i, 'unused') + + # Remove up to 15 bytes of padding at the end + end_padding = 0 + for i in range(len(data) - 1, -1, -1): + if output[i] is not None: + break + end_padding += 1 + if end_padding > 15: + end_padding = 0 + + if print_end_padding: + print(end_padding) + sys.exit(0) + + header_str = os.path.splitext(os.path.basename(header.name))[0] + header_id = soundfonts[int(header_str)] if header_str.isdigit() else header_str + + if cachePolicy != 2: + policyname = { + "0": "CACHE_PERMANENT", + "1": "CACHE_PERSISTENT", + "2": "CACHE_TEMPORARY", + "3": "CACHE_ANY", + "4": "CACHE_ANYNOSYNC" + }.get(cachePolicy) + print(f".cache {policyname}") + print(f".usefont {header_id}") + print() + print(".sequence sequence_start") + last_tp = "" + for i in range(len(data) - end_padding): + if script_start[i] and i > 0: + print() + tp = output_instate[i][1] if output_instate[i] else '' + if tp != last_tp and alignment[i] is not None: + print(f".balign {alignment[i]}\n") + last_tp = tp + if label_name[i] is not None: + print(f".{label_kind[i]} {label_name[i]}") + o = output[i] + if o is None: + print(f"byte {hex(data[i]).upper()}") + elif o: + print(o) + elif label_name[i] is not None: + print("") + errors.append(f"mid-instruction label {label_name[i]}") + + if not data: + print("# empty") + elif hit_eof: + errors.append("hit eof!?") + + if errors: + print(f"[{filename}] errors:", file=sys.stderr) + for w in errors: + print(w, file=sys.stderr) + +main() diff --git a/tools/disassemble_sequences.py b/tools/disassemble_sequences.py new file mode 100644 index 00000000000..a4bcf5e96b3 --- /dev/null +++ b/tools/disassemble_sequences.py @@ -0,0 +1,151 @@ +#!/usr/bin/env python3 +import argparse +from pathlib import Path +import subprocess +import tempfile +from xml.dom import minidom +import xml.etree.ElementTree as XmlTree +import os +import json +import struct +import sys + +from audio_common import toCachePolicy, toMedium + +refseqs = {} + +offsets = { + "MQDebug": { + "bankdefs": [1281424, 128], + "fontdefs": [1278576, 624], + "fontmaps": [1279200, 448], + "seqdefs": [1279648, 1776] + } +} + +class SequenceEntry: + def __init__(self, data): + self.offset, self.length, self.medium, self.cache = struct.unpack(">LLBBxxxxxx", data) + +def parse_seq_def_data(seqdef_data, seq_data): + count = struct.unpack(">H", seqdef_data[:2])[0] + entries = [] + for i in range(count): + entry = SequenceEntry(seqdef_data[16 + (i * 16):32 + (i * 16)]) + entries.append(entry) + for index in range(len(entries)): + entry = entries[index] + if entry.length == 0: + refseqs[index] = entry + else: + entry.sequence = seq_data[entry.offset:entry.offset + entry.length] + return entries + +def convert_aseq_to_mus(aseq_name, mus_name, font_path, seqinc, cacheid): + seqdecode = os.path.join(os.path.dirname(__file__), "disassemble_sequence.py") + common_dir = os.getcwd() + rel_seqdecode = "./" + os.path.relpath(seqdecode, common_dir).replace("\\", "/") + output_file = open(mus_name, "w", encoding="utf8") + try: + subprocess.run(["python3", rel_seqdecode, aseq_name, font_path, seqinc, "--cache-policy", str(cacheid)], check=True, stdout=output_file) + except subprocess.CalledProcessError: + exit(f"failed to convert {aseq_name} to mus format (header was {os.path.basename(font_path)})") + finally: + output_file.close() + +def get_soundfont_ids_for_seq(index, data): + seq_idx = struct.unpack(">h", data[index * 2: index * 2 + 2])[0] + count = struct.unpack(">b", data[seq_idx:seq_idx + 1])[0] + assert count == 1 + return struct.unpack(">b", data[seq_idx + 1:seq_idx + 2])[0] + +def main(args): + table_offsets = offsets + version = args.version + + # code file + code_data = args.code.read() + seq_data = args.audioseq.read() + seq_def = args.seqdef + soundfont_inc_path = args.fontinc + midi_out_dir = args.output + + def check_offset(offset, type): + if offset is None: + print(f"Offsets JSON file is missing a {type} offset for version {version}", file=sys.stderr) + sys.exit(1) + return offset + + if table_offsets[version] is None: + print(f"Offsets JSON file does not contain version {version}", file=sys.stderr) + sys.exit(1) + + seqdef_offset, seqdef_length = check_offset(table_offsets[version]["seqdefs"], "seqdefs") + seqmap_offset, seqmap_length = check_offset(table_offsets[version]["fontmaps"], "fontmaps") + + seqdef_data = code_data[seqdef_offset:seqdef_offset + seqdef_length] + seqmap_data = code_data[seqmap_offset:seqmap_offset + seqmap_length] + + # Import sequence names + xml = XmlTree.parse(seq_def) + sequence_names = xml.findall("./Sequence") + + # Export sequences + sequences = parse_seq_def_data(seqdef_data, seq_data) + + for idx in range(len(sequences)): + name = sequence_names[idx] + sequence = sequences[idx] + + if name.get("Extract") == "false": + continue + + font_id = get_soundfont_ids_for_seq(idx, seqmap_data) + dir = os.path.join(midi_out_dir) + os.makedirs(dir, exist_ok=True) + aseq_dir = tempfile.mkdtemp(prefix=f"{version}_", suffix="_aseq") + seq_name = name.get("Name") if name.get("Name") else f"{sequence.offset:08x}" + with open(os.path.join(aseq_dir, f"{seq_name}.aseq"), "wb") as aseq: + aseq.write(sequence.sequence) + aseq.flush() + mus_file = os.path.join(dir, f"{seq_name}.seq") + if not os.path.exists(mus_file) or os.path.getsize(mus_file) == 0: + convert_aseq_to_mus(aseq.name, mus_file, os.path.join(soundfont_inc_path, f"{font_id}.inc"), args.seqinc, sequence.cache) + + if len(refseqs.keys()) > 0: + with open(os.path.join(midi_out_dir, "References.xml"), "w") as refxml: + root = XmlTree.Element("References") + + for k, v in refseqs.items(): + seqentry = sequence_names[k] + targetentry = sequence_names[v.offset] + target_name = targetentry.get("Name") if targetentry.get("Name") else f"{v.offset:08x}" + sequence_name = seqentry.get("Name") if seqentry.get("Name") else f"{k:08x}" + XmlTree.SubElement( + root, + "Reference", + { + "Name": sequence_name, + "Target": f"{target_name}.seq", + "Medium": toMedium(v.medium), + "CachePolicy": toCachePolicy(v.cache) + } + ) + + xmlstring = XmlTree.tostring(root, "unicode") + prettyxml = minidom.parseString(xmlstring).toprettyxml(indent="\t") + refxml.write(prettyxml) + +if __name__ == "__main__": + parser = argparse.ArgumentParser(add_help=False) + parser.add_argument("version", metavar="", help="The version of Ocarina of Time being disassembled.") + parser.add_argument("code", metavar="", type=argparse.FileType("rb"), help="Path to the 'code' file, usually in baserom.") + parser.add_argument("audioseq", metavar="", type=argparse.FileType("rb"), help="Path to the 'Audioseq' file, usually in baserom.") + parser.add_argument("seqdef", metavar="", type=argparse.FileType("r"), help="The asset XML where the sequence definitions are stored.") + parser.add_argument("fontinc", metavar="", type=Path, help="The path to the soundfont inc files.") + parser.add_argument("seqinc", metavar="", type=Path, help="The path to the sequence.inc file.") + parser.add_argument("output", metavar="", type=Path, help="The output path for sequences.") + parser.add_argument("--help", "-h", "-?", action="help", help="Show this help message and exit.") + args = parser.parse_args() + + main(args) diff --git a/tools/disassemble_sound.py b/tools/disassemble_sound.py new file mode 100644 index 00000000000..bfcf0a1b22f --- /dev/null +++ b/tools/disassemble_sound.py @@ -0,0 +1,552 @@ +#!/usr/bin/env python3 +import argparse +from audio_common import * +from collections import defaultdict +from pathlib import Path +from xml.dom import minidom +import subprocess +import math +import shutil +import xml.etree.ElementTree as XmlTree +import json +import os +import struct +import sys + +usedTuning = {} +refBanks = {} + +# Used for data gap detection (finding potentially unreferenced data) +# Format: list of tuples (object, start offset, end offset) +usedFontData = [] +usedRawData = [] + +offsets = { + "MQDebug": { + "bankdefs": [1281424, 128], + "fontdefs": [1278576, 624], + "fontmaps": [1279200, 448], + "seqdefs": [1279648, 1776] + } +} + +fixups = { + "MQDebug": { + "0": { + "0x2A50": ["Envelope", 16], + "0x2A80": ["Envelope", 12], + "0x2A90": ["Envelope", 16] + } + } +} + +def parse_raw_def_data(raw_def_data, samplebanks): + count = struct.unpack(">H", raw_def_data[:2])[0] + entries = [] + + for i in range(count): + buffer = raw_def_data[16 + (i * 16):32 + (i * 16)] + entry = SampleTableEntry(samplebanks[i] or str(i)) + entry.parseFrom(buffer) + entry.index = i + entries.append(entry) + + for i in range(len(entries)): + entry = entries[i] + + if entry.length == 0: + refBanks[i] = entry.offset + if entry.offset not in usedTuning: + usedTuning[entry.offset] = {} + if i in usedTuning: + usedTuning[entry.offset].update(usedTuning[i]) + usedTuning[i] = usedTuning[entry.offset] + samplebanks[i] = samplebanks[entry.offset] + + return entries + +def parse_soundfonts(fontdef_data, font_data, fontdefs): + count = struct.unpack(">H", fontdef_data[:2])[0] + fonts = [] + for i in range(count): + fontdef = fontdefs[i] + buffer = fontdef_data[16 + (i * 16):32 + (i * 16)] + entry = SoundfontEntry() + entry.parseFrom(buffer) + font = Soundfont() + font.parseFrom(entry, font_data, fontdef, usedFontData) + fonts.append(font) + return fonts + +class SoundfontDefinition: + def __init__(self, name, symbol, index, bankOverride) -> None: + self.name = name or "" + self.bankOverride = bankOverride or None + self.index = index or -1 + self.symbol = symbol + self.instruments = [] + self.drums = [] + self.effects = [] + +class ElementDefinition: + def __init__(self, name, enum) -> None: + self.name = name + self.enum = enum + +def read_soundfont_xmls(xml_dir): + results = defaultdict(lambda: None) + + for file in os.listdir(xml_dir): + if file.endswith(".xml"): + xml = XmlTree.parse(os.path.join(xml_dir, file)) + soundfontElement = xml.find("./Soundfont") + soundfont = SoundfontDefinition( + soundfontElement.get("Name"), + soundfontElement.get("Symbol"), + soundfontElement.get("Index"), + soundfontElement.get("OverrideSampleBank") + ) + instrumentsElement = soundfontElement.find("Instruments") + instrumentElements = (instrumentsElement and instrumentsElement.findall("Instrument")) or [] + drumsElement = soundfontElement.find("Drums") + drumElements = (drumsElement and drumsElement.findall("Drum")) or [] + effectsElement = soundfontElement.find("Effects") + effectsElements = (effectsElement and effectsElement.findall("Effect")) or [] + + for instrumentElement in instrumentElements: + instrument = ElementDefinition(instrumentElement.get("Name"), instrumentElement.get("Enum")) + soundfont.instruments.append(instrument) + + for drumElement in drumElements: + drum = ElementDefinition(drumElement.get("Name"), drumElement.get("Enum")) + soundfont.drums.append(drum) + + for effectElement in effectsElements: + effect = ElementDefinition(effectElement.get("Name"), effectElement.get("Enum")) + soundfont.effects.append(effect) + + results[int(soundfont.index)] = soundfont + + return results + +def read_samplebank_xml(xml_dir, version, sampleNames): + results = defaultdict(lambda: None) + + for xmlfile in os.listdir(xml_dir): + if xmlfile.endswith(".xml"): + bankname = os.path.splitext(xmlfile)[0] + index = int(bankname.split(" ")[0]) + results[index] = bankname + root = XmlTree.parse(os.path.join(xml_dir, xmlfile)) + for sample in root.findall("Sample"): + offsetElement = sample.find(f"./Offset[@Version='{version}']") + if offsetElement == None: + continue + offset = int(offsetElement.get("At"), 0) + if index not in sampleNames: + sampleNames[index] = defaultdict(lambda: None) + if offset not in sampleNames[index]: + sampleNames[index][offset] = sample.get("Name") + if "SampleRate" in sample.attrib: + if index not in usedTuning: + usedTuning[index] = {} + usedTuning[index][offset] = float(int(sample.get("SampleRate")) / 32000.0) + return results + +def sort_data(data): + seen = set() + results = [] + + for obj, start, end in data: + objUniqKey = (obj.__class__, start, end) + if objUniqKey not in seen: + seen.add(objUniqKey) + results.append((obj, start, end)) + + sortedResults = sorted(set(results), key=lambda tup: (tup[1], tup[2])) + + return sortedResults + +def report_gaps(report_type, data, bin): + length = len(bin) + sorted_data = sort_data(data) + gaps = set() + intersections = [] + lastTuple = (None, -1, -1) + currentEnd = 0 + for tup in sorted_data: + if tup[1] > currentEnd: + # Don't report a gap of all 0 bytes, since those are generally just alignment padding + if any(v != 0 for v in struct.unpack(f">{tup[1] - currentEnd}b", bin[currentEnd:tup[1]])): + gaps.add((currentEnd, tup[1])) + elif tup[1] < currentEnd and (lastTuple[1] != tup[1] or lastTuple[2] != tup[2]): + intersections.append((lastTuple, tup)) + lastTuple = tup + if report_type == "SOUNDFONT": + currentEnd = tup[2] + else: + alignEnd = (16 * math.ceil(tup[2] / 16)) + if any(v != 0 for v in struct.unpack(f">{alignEnd - tup[2]}b", bin[tup[2]:alignEnd])): + gaps.add((tup[2], alignEnd)) + currentEnd = alignEnd + if currentEnd < length: + bytes = struct.unpack(f">{length - currentEnd}b", bin[currentEnd:length]) + if any(b != 0 for b in bytes): + gaps.add((sorted_data[-1][2], length)) + if len(gaps) > 0: + print(f"GAPS DETECTED IN {report_type} DATA:") + for gap in gaps: + print(f"Unreferenced data at {gap[0]:08X}-{gap[1]:08X} ({gap[1] - gap[0]} bytes)") + if len(intersections) > 0: + print(f"INTERSECTIONS DETECTED IN {report_type} DATA:") + for cross in intersections: + print(f"{type(cross[0][0]).__name__} at {cross[0][1]:08X}-{cross[0][2]:08X} overlaps {type(cross[1][0]).__name__} at {cross[1][1]:08X}-{cross[1][2]:08X}") + +def get_data_gaps(report_type, data, bin): + results = {} + length = len(bin) + sorted_data = sorted(data, key = lambda tup: (tup[1], tup[2])) + intersections = [] + lastTuple = (None, -1, -1) + currentEnd = 0 + for tup in sorted_data: + if tup[1] > currentEnd: + bytes = struct.unpack(f">{tup[1] - currentEnd}b", bin[currentEnd:tup[1]]) + if any(b != 0 for b in bytes): + results[currentEnd] = bin[currentEnd:tup[1]] + elif tup[1] < currentEnd and (lastTuple[1] != tup[1] or lastTuple[2] != tup[2]): + intersections.append((lastTuple, tup)) + lastTuple = tup + if report_type == "SOUNDFONT": + currentEnd = tup[2] + else: + alignEnd = (16 * math.ceil(tup[2] / 16)) + if any(v != 0 for v in struct.unpack(f">{alignEnd - tup[2]}b", bin[tup[2]:alignEnd])): + results[tup[2]] = bin[tup[2]:alignEnd] + currentEnd = alignEnd + if currentEnd < length: + bytes = struct.unpack(f">{length - currentEnd}b", bin[currentEnd:length]) + if any(b != 0 for b in bytes): + results[currentEnd] = bytes + if len(intersections) > 0: + print(f"INTERSECTIONS DETECTED IN {report_type} DATA:") + for cross in intersections: + print(f"{type(cross[0][0]).__name__} at {cross[0][1]:08X}-{cross[0][2]:08X} overlaps {type(cross[1][0]).__name__} at {cross[1][1]:08X}-{cross[1][2]:08X}") + return results + +def getTuning(tunings): + # In order of best candidates + acceptedSampleRates = [32000, 16000, 22050, 10000, 22000, 24000, 20000] + candidates = [32000 * tuning for tuning in tunings] + + for i in range(len(tunings)): + tuning = tunings[i] + candidate = candidates[i] + + if candidate in acceptedSampleRates: + return tuning + + for accepted in acceptedSampleRates: + if abs(accepted - candidate) < 1000.0: + return float(accepted / 32000.0) + + # Seems to sound like the default for most samples with bad sample rates + return 0.5 + +def write_aifc(raw, bank_defs, entry, filename, tunings): + offset = bank_defs[entry.bank].offset + entry.offsetInBank + length = entry.length + data = raw[offset:offset + length] + usedRawData.append((entry, offset, offset + length)) + frame_size = { + 0: 9, + 1: 16, + 2: 32, + 3: 5, + 4: 0, + 5: 32 + }.get(entry.codec) + sample_size = 16 # bits per sample + + sampleTunings = tunings[entry.bank][entry.offsetInBank].copy() + + assert sampleTunings is not None + assert len(sampleTunings) > 0 + + if entry.bank not in usedTuning: + usedTuning[entry.bank] = {} + + if entry.bank in usedTuning and entry.offsetInBank in usedTuning[entry.bank]: + tuning = usedTuning[entry.bank][entry.offsetInBank] + else: + tuning = getTuning(list(sampleTunings)) + usedTuning[entry.bank][entry.offsetInBank] = tuning + + sample_rate = 32000 * tuning + + if not os.path.exists(filename) or os.path.getsize(filename) == 0: + with open(filename, "wb") as file: + writer = AifcWriter(file) + num_channels = 1 + if len(data) % 2 == 1: + data += b"\0" + # (Computing num_frames this way makes it off by one when the data length + # is odd. It matches vadpcm_enc, though.) + num_frames = len(data) * sample_size // frame_size + + writer.add_section( + b"COMM", + struct.pack(">hIh", num_channels, num_frames, sample_size) + + serialize_f80(sample_rate) + + toCodecID(entry.codec) + + writer.pstring(toCodecName(entry.codec)), + ) + writer.add_section(b"INST", b"\0" * 20) + predictors = [] + for table in entry.book.predictors: + for predictor in table: + predictors.append(predictor) + table_data = b"".join(struct.pack(">h", x) for x in predictors) + writer.add_custom_section( + b"VADPCMCODES", + struct.pack(">hhh", 1, entry.book.order, entry.book.predictorCount) + table_data, + ) + writer.add_section(b"SSND", struct.pack(">II", 0, 0) + data) + if entry.loop.count != 0: + writer.add_custom_section( + b"VADPCMLOOPS", + struct.pack( + ">HHIIi16h", + 1, + 1, + entry.loop.start, + entry.loop.end, + entry.loop.count, + *entry.loop.predictorState + ), + ) + writer.finish() + +def write_aiff(entry, basedir, aifc_filename, aiff_filename): + rel_aiff_file = os.path.join(os.path.dirname(aifc_filename).replace("\\", "/"), aiff_filename) + if not os.path.exists(rel_aiff_file) or os.path.getsize(rel_aiff_file) == 0 or os.path.exists(os.path.join(basedir, "bad", str(entry.bank), os.path.basename(aifc_filename))): + try: + frame_size = "" if entry.codec == 0 else "5" + aifc_decode = os.path.join(os.path.dirname(__file__), "aifc_decode") + common_dir = os.getcwd() + rel_aifc_decode = "./" + os.path.relpath(aifc_decode, common_dir).replace("\\", "/") + os.makedirs(os.path.dirname(rel_aiff_file), exist_ok=True) + subprocess.run(["bash", "-c", f"{rel_aifc_decode} \"{aifc_filename}\" \"{rel_aiff_file}\" {frame_size}"], check=True) + except subprocess.CalledProcessError: + print(f"File failed to decode {rel_aifc_decode}, codec was {entry.codec}") + targetfile = os.path.join(basedir, "bad", str(entry.bank), os.path.basename(aifc_filename)) + os.makedirs(os.path.dirname(targetfile), exist_ok=True) + os.remove(rel_aiff_file) + shutil.copy2(aifc_filename, targetfile) + +def write_soundfont(font, filename, samplebanks, sampleNames, tunings): + with open(filename, "w") as file: + xml = font.toXML(samplebanks, sampleNames, tunings) + xmlstring = minidom.parseString(XmlTree.tostring(xml, "unicode")).toprettyxml(indent="\t") + file.write(xmlstring) + +def populateRawSamples(fonts): + rawSamples = {} + + for font in fonts: + for sample in font.getSamples(): + if sample.bank not in rawSamples: + if sample.bank in refBanks: + if refBanks[sample.bank] not in rawSamples: + rawSamples[refBanks[sample.bank]] = {} + rawSamples[sample.bank] = rawSamples[refBanks[sample.bank]] + else: + rawSamples[sample.bank] = {} + if sample.offsetInBank not in rawSamples[sample.bank]: + rawSamples[sample.bank][sample.offsetInBank] = sample + + return rawSamples + +def populateSampleNames(fonts, sampleNames): + for font in fonts: + for sample in font.getSamples(): + if sample.bank not in sampleNames: + sampleNames[sample.bank] = {} + if sample.offsetInBank not in sampleNames[sample.bank]: + sampleNames[sample.bank][sample.offsetInBank] = sample.name + +def populateTunings(fonts): + tunings = {} + + for font in fonts: + for sample in font.getSamples(): + if sample.bank not in tunings: + if sample.bank in refBanks: + if refBanks[sample.bank] not in tunings: + tunings[refBanks[sample.bank]] = {} + tunings[sample.bank] = tunings[refBanks[sample.bank]] + else: + tunings[sample.bank] = {} + if sample.offsetInBank not in tunings[sample.bank]: + tunings[sample.bank][sample.offsetInBank] = set() + tunings[sample.bank][sample.offsetInBank].add(sample.tuning) + + return tunings + +def main(args): + table_offsets = offsets + sf_unused_fixups = fixups + + version = args.version + # code file + code_data = args.code.read() + bank_data = args.audiotable.read() + font_data = args.audiobank.read() + asset_xml_dir = args.assetxml + samples_out_dir = args.sampleout + fonts_out_dir = args.fontout + + def check_dir(path): + if not os.path.isdir(path): + print(f"{path} must be a directory!", file=sys.stderr) + sys.exit(1) + + check_dir(os.path.join(asset_xml_dir, "samples")) + check_dir(os.path.join(asset_xml_dir, "soundfonts")) + + def check_offset(offset, type): + if offset is None: + print(f"Offsets JSON file is missing a {type} offset for version {version}", file=sys.stderr) + sys.exit(1) + return offset + + if table_offsets[version] is None: + print(f"Offsets JSON file does not contain version {version}", file=sys.stderr) + sys.exit(1) + + bankdef_offset, bankdef_length = check_offset(table_offsets[version]["bankdefs"], "bankdefs") + fontdef_offset, fontdef_length = check_offset(table_offsets[version]["fontdefs"], "fontdefs") + + bankdef_data = code_data[bankdef_offset:bankdef_offset + bankdef_length] + fontdef_data = code_data[fontdef_offset:fontdef_offset + fontdef_length] + sampleNames = {} + + soundfont_defs = read_soundfont_xmls(os.path.join(asset_xml_dir, "soundfonts")) + samplebanks = read_samplebank_xml(os.path.join(asset_xml_dir, "samples"), version, sampleNames) + real_samplebanks = dict(samplebanks) + + bank_defs = parse_raw_def_data(bankdef_data, samplebanks) + fonts = parse_soundfonts(fontdef_data, font_data, soundfont_defs) + + def get_entry_from_absolute_offset(table, offset): + table_clone = [x for x in table if x.length != 0] + + for i in range(len(table_clone)): + currentOffset = table_clone[i].offset + nextOffset = table_clone[i + 1].offset if i < len(table_clone) - 1 else sys.maxsize + if currentOffset <= offset and offset < nextOffset: + return table_clone[i] + + rawSamples = populateRawSamples(fonts) + populateSampleNames(fonts, sampleNames) + tunings = populateTunings(fonts) + + for fontIdStr in sf_unused_fixups[version]: + fontId = int(fontIdStr) + font = fonts[fontId] + for offsetStr in sf_unused_fixups[version][fontIdStr]: + offset = int(offsetStr, 0) + fixup = sf_unused_fixups[version][fontIdStr][offsetStr] + datatype = fixup[0] + length = fixup[1] + def makeEnvelope(data, baseOffset, offset): + env = Envelope() + env.parseFrom(data, baseOffset, offset, usedFontData) + return env + converted_data = { + "Envelope": makeEnvelope(font_data, font.offset, offset) + }.get(datatype) + font.unused.append(converted_data) + + if args.gaps: + report_gaps("SOUNDFONT", usedFontData, font_data) + soundfont_gaps = get_data_gaps("SOUNDFONT", usedFontData, font_data) + + for offset in soundfont_gaps: + font = get_entry_from_absolute_offset(fonts, offset) + data_wrapper = UnusedData(offset, soundfont_gaps[offset]) + font.unused.append(data_wrapper) + + os.makedirs(samples_out_dir, exist_ok=True) + + with open(os.path.join(samples_out_dir, "Banks.xml"), "w") as bankdeffile: + bankdefxml = XmlTree.Element("SampleBanks") + for bankdef in bank_defs: + if bankdef.length == 0: + XmlTree.SubElement(bankdefxml, "SampleBank", { + "Reference": bank_defs[bankdef.offset].name + }) + else: + XmlTree.SubElement(bankdefxml, "SampleBank", { + "Name": bankdef.name, + "CachePolicy": toCachePolicy(bankdef.cache), + "Medium": toMedium(bankdef.medium) + }) + xmlstring = minidom.parseString(XmlTree.tostring(bankdefxml, "unicode")).toprettyxml(indent="\t") + bankdeffile.write(xmlstring) + + # Export AIFF samples + for bank in rawSamples: + rawSamples[bank] = dict(sorted(rawSamples[bank].items())) + idx = 0 + width = len(str(len(rawSamples[bank]))) + for address in rawSamples[bank]: + sample = rawSamples[bank][address] + filename_base = os.path.join(samples_out_dir, samplebanks[bank]) + sampleName = sampleNames[sample.bank][sample.offsetInBank] + os.makedirs(filename_base, exist_ok=True) + aifc_filename = os.path.join(filename_base, f"{str(idx).zfill(width)} {sampleName}.aifc") + aiff_filename = f"{str(idx).zfill(width)} {sampleName}.aiff" + write_aifc(bank_data, bank_defs, sample, aifc_filename, tunings) + write_aiff(sample, samples_out_dir, aifc_filename, aiff_filename) + idx += 1 + + if len(usedRawData) > 0: + if args.gaps: + report_gaps("SAMPLE", usedRawData, bank_data) + samplebank_gaps = get_data_gaps("SAMPLE", usedRawData, bank_data) + for offset in samplebank_gaps: + bank = get_entry_from_absolute_offset(bank_defs, offset) + filename = os.path.join(samples_out_dir, bank.name, f"{offset:0>8x} - Unused.bin") + os.makedirs(os.path.dirname(filename), exist_ok=True) + with open(filename, "wb") as bin_file: + bin_file.write(samplebank_gaps[offset]) + + os.makedirs(args.fontinc, exist_ok=True) + # Export soundfonts + for font in fonts: + dir = os.path.join(fonts_out_dir) + os.makedirs(dir, exist_ok=True) + filename = os.path.join(dir, f"{font.name}.xml") + if font.name[0:1].isnumeric(): + idx = font.name.find('_') + if idx >= 0: + font.name = font.name[idx + 1:] + + write_soundfont(font, filename, real_samplebanks, sampleNames, tunings) + write_soundfont_define(font, len(fonts), os.path.join(args.fontinc, f"{font.idx}.inc")) + +if __name__ == "__main__": + parser = argparse.ArgumentParser(add_help=False) + parser.add_argument("version", metavar="", help="The version of Ocarina of Time being disassembled.") + parser.add_argument("code", metavar="", type=argparse.FileType("rb"), help="Path to the 'code' file, usually in baserom.") + parser.add_argument("audiotable", metavar="", type=argparse.FileType("rb"), help="Path to the 'AudioTable' file, usually in baserom.") + parser.add_argument("audiobank", metavar="", type=argparse.FileType("rb"), help="Path to the 'Audiobank' file, usually in baserom.") + parser.add_argument("assetxml", metavar="", type=Path, help="The asset XML path where the definitions are stored.") + parser.add_argument("sampleout", metavar="", type=Path, help="The output path for extracted samples.") + parser.add_argument("fontout", metavar="", type=Path, help="The output path for extracted soundfonts.") + parser.add_argument("fontinc", metavar="", type=Path, help="The output path for generated soundfont include files.") + parser.add_argument("--help", "-h", "-?", action="help", help="Show this help message and exit.") + parser.add_argument("--detect-gaps", "-g", dest="gaps", action='store_true', help="Outputs unreferenced data ranges to standard out.") + args = parser.parse_args() + main(args) diff --git a/tools/elfio/elf_types.hpp b/tools/elfio/elf_types.hpp new file mode 100644 index 00000000000..b99c35f386a --- /dev/null +++ b/tools/elfio/elf_types.hpp @@ -0,0 +1,1080 @@ +/* +Copyright (C) 2001-present by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELFTYPES_H +#define ELFTYPES_H + +#ifdef __cplusplus +namespace ELFIO { +#endif + +using Elf_Half = uint16_t; +using Elf_Word = uint32_t; +using Elf_Sword = int32_t; +using Elf_Xword = uint64_t; +using Elf_Sxword = int64_t; + +using Elf32_Addr = uint32_t; +using Elf32_Off = uint32_t; +using Elf64_Addr = uint64_t; +using Elf64_Off = uint64_t; + +using Elf32_Half = Elf_Half; +using Elf64_Half = Elf_Half; +using Elf32_Word = Elf_Word; +using Elf64_Word = Elf_Word; +using Elf32_Sword = Elf_Sword; +using Elf64_Sword = Elf_Sword; + +/////////////////////// +// ELF Header Constants + +// File type +constexpr Elf_Half ET_NONE = 0; +constexpr Elf_Half ET_REL = 1; +constexpr Elf_Half ET_EXEC = 2; +constexpr Elf_Half ET_DYN = 3; +constexpr Elf_Half ET_CORE = 4; +constexpr Elf_Half ET_LOOS = 0xFE00; +constexpr Elf_Half ET_HIOS = 0xFEFF; +constexpr Elf_Half ET_LOPROC = 0xFF00; +constexpr Elf_Half ET_HIPROC = 0xFFFF; + +// clang-format off +// Machine number +constexpr Elf_Half EM_NONE = 0 ; // No machine +constexpr Elf_Half EM_M32 = 1 ; // AT&T WE 32100 +constexpr Elf_Half EM_SPARC = 2 ; // SUN SPARC +constexpr Elf_Half EM_386 = 3 ; // Intel 80386 +constexpr Elf_Half EM_68K = 4 ; // Motorola m68k family +constexpr Elf_Half EM_88K = 5 ; // Motorola m88k family +constexpr Elf_Half EM_486 = 6 ; // Intel 80486// Reserved for future use +constexpr Elf_Half EM_860 = 7 ; // Intel 80860 +constexpr Elf_Half EM_MIPS = 8 ; // MIPS R3000 (officially, big-endian only) +constexpr Elf_Half EM_S370 = 9 ; // IBM System/370 +constexpr Elf_Half EM_MIPS_RS3_LE = 10; // MIPS R3000 little-endian (Deprecated) +constexpr Elf_Half EM_res011 = 11; // Reserved +constexpr Elf_Half EM_res012 = 12; // Reserved +constexpr Elf_Half EM_res013 = 13; // Reserved +constexpr Elf_Half EM_res014 = 14; // Reserved +constexpr Elf_Half EM_PARISC = 15; // HPPA +constexpr Elf_Half EM_res016 = 16; // Reserved +constexpr Elf_Half EM_VPP550 = 17; // Fujitsu VPP500 +constexpr Elf_Half EM_SPARC32PLUS = 18; // Sun's "v8plus" +constexpr Elf_Half EM_960 = 19; // Intel 80960 +constexpr Elf_Half EM_PPC = 20; // PowerPC +constexpr Elf_Half EM_PPC64 = 21; // 64-bit PowerPC +constexpr Elf_Half EM_S390 = 22; // IBM S/390 +constexpr Elf_Half EM_SPU = 23; // Sony/Toshiba/IBM SPU +constexpr Elf_Half EM_res024 = 24; // Reserved +constexpr Elf_Half EM_res025 = 25; // Reserved +constexpr Elf_Half EM_res026 = 26; // Reserved +constexpr Elf_Half EM_res027 = 27; // Reserved +constexpr Elf_Half EM_res028 = 28; // Reserved +constexpr Elf_Half EM_res029 = 29; // Reserved +constexpr Elf_Half EM_res030 = 30; // Reserved +constexpr Elf_Half EM_res031 = 31; // Reserved +constexpr Elf_Half EM_res032 = 32; // Reserved +constexpr Elf_Half EM_res033 = 33; // Reserved +constexpr Elf_Half EM_res034 = 34; // Reserved +constexpr Elf_Half EM_res035 = 35; // Reserved +constexpr Elf_Half EM_V800 = 36; // NEC V800 series +constexpr Elf_Half EM_FR20 = 37; // Fujitsu FR20 +constexpr Elf_Half EM_RH32 = 38; // TRW RH32 +constexpr Elf_Half EM_MCORE = 39; // Motorola M*Core // May also be taken by Fujitsu MMA +constexpr Elf_Half EM_RCE = 39; // Old name for MCore +constexpr Elf_Half EM_ARM = 40; // ARM +constexpr Elf_Half EM_OLD_ALPHA = 41; // Digital Alpha +constexpr Elf_Half EM_SH = 42; // Renesas (formerly Hitachi) / SuperH SH +constexpr Elf_Half EM_SPARCV9 = 43; // SPARC v9 64-bit +constexpr Elf_Half EM_TRICORE = 44; // Siemens Tricore embedded processor +constexpr Elf_Half EM_ARC = 45; // ARC Cores +constexpr Elf_Half EM_H8_300 = 46; // Renesas (formerly Hitachi) H8/300 +constexpr Elf_Half EM_H8_300H = 47; // Renesas (formerly Hitachi) H8/300H +constexpr Elf_Half EM_H8S = 48; // Renesas (formerly Hitachi) H8S +constexpr Elf_Half EM_H8_500 = 49; // Renesas (formerly Hitachi) H8/500 +constexpr Elf_Half EM_IA_64 = 50; // Intel IA-64 Processor +constexpr Elf_Half EM_MIPS_X = 51; // Stanford MIPS-X +constexpr Elf_Half EM_COLDFIRE = 52; // Motorola Coldfire +constexpr Elf_Half EM_68HC12 = 53; // Motorola M68HC12 +constexpr Elf_Half EM_MMA = 54; // Fujitsu Multimedia Accelerator +constexpr Elf_Half EM_PCP = 55; // Siemens PCP +constexpr Elf_Half EM_NCPU = 56; // Sony nCPU embedded RISC processor +constexpr Elf_Half EM_NDR1 = 57; // Denso NDR1 microprocesspr +constexpr Elf_Half EM_STARCORE = 58; // Motorola Star*Core processor +constexpr Elf_Half EM_ME16 = 59; // Toyota ME16 processor +constexpr Elf_Half EM_ST100 = 60; // STMicroelectronics ST100 processor +constexpr Elf_Half EM_TINYJ = 61; // Advanced Logic Corp. TinyJ embedded processor +constexpr Elf_Half EM_X86_64 = 62; // Advanced Micro Devices X86-64 processor +constexpr Elf_Half EM_PDSP = 63; // Sony DSP Processor +constexpr Elf_Half EM_PDP10 = 64; // Digital Equipment Corp. PDP-10 +constexpr Elf_Half EM_PDP11 = 65; // Digital Equipment Corp. PDP-11 +constexpr Elf_Half EM_FX66 = 66; // Siemens FX66 microcontroller +constexpr Elf_Half EM_ST9PLUS = 67; // STMicroelectronics ST9+ 8/16 bit microcontroller +constexpr Elf_Half EM_ST7 = 68 ; // STMicroelectronics ST7 8-bit microcontroller +constexpr Elf_Half EM_68HC16 = 69 ; // Motorola MC68HC16 Microcontroller +constexpr Elf_Half EM_68HC11 = 70 ; // Motorola MC68HC11 Microcontroller +constexpr Elf_Half EM_68HC08 = 71 ; // Motorola MC68HC08 Microcontroller +constexpr Elf_Half EM_68HC05 = 72 ; // Motorola MC68HC05 Microcontroller +constexpr Elf_Half EM_SVX = 73 ; // Silicon Graphics SVx +constexpr Elf_Half EM_ST19 = 74 ; // STMicroelectronics ST19 8-bit cpu +constexpr Elf_Half EM_VAX = 75 ; // Digital VAX +constexpr Elf_Half EM_CRIS = 76 ; // Axis Communications 32-bit embedded processor +constexpr Elf_Half EM_JAVELIN = 77 ; // Infineon Technologies 32-bit embedded cpu +constexpr Elf_Half EM_FIREPATH = 78 ; // Element 14 64-bit DSP processor +constexpr Elf_Half EM_ZSP = 79 ; // LSI Logic's 16-bit DSP processor +constexpr Elf_Half EM_MMIX = 80 ; // Donald Knuth's educational 64-bit processor +constexpr Elf_Half EM_HUANY = 81 ; // Harvard's machine-independent format +constexpr Elf_Half EM_PRISM = 82 ; // SiTera Prism +constexpr Elf_Half EM_AVR = 83 ; // Atmel AVR 8-bit microcontroller +constexpr Elf_Half EM_FR30 = 84 ; // Fujitsu FR30 +constexpr Elf_Half EM_D10V = 85 ; // Mitsubishi D10V +constexpr Elf_Half EM_D30V = 86 ; // Mitsubishi D30V +constexpr Elf_Half EM_V850 = 87 ; // NEC v850 +constexpr Elf_Half EM_M32R = 88 ; // Renesas M32R (formerly Mitsubishi M32R) +constexpr Elf_Half EM_MN10300 = 89 ; // Matsushita MN10300 +constexpr Elf_Half EM_MN10200 = 90 ; // Matsushita MN10200 +constexpr Elf_Half EM_PJ = 91 ; // picoJava +constexpr Elf_Half EM_OPENRISC = 92 ; // OpenRISC 32-bit embedded processor +constexpr Elf_Half EM_ARC_A5 = 93 ; // ARC Cores Tangent-A5 +constexpr Elf_Half EM_XTENSA = 94 ; // Tensilica Xtensa Architecture +constexpr Elf_Half EM_VIDEOCORE = 95 ; // Alphamosaic VideoCore processor +constexpr Elf_Half EM_TMM_GPP = 96 ; // Thompson Multimedia General Purpose Processor +constexpr Elf_Half EM_NS32K = 97 ; // National Semiconductor 32000 series +constexpr Elf_Half EM_TPC = 98 ; // Tenor Network TPC processor +constexpr Elf_Half EM_SNP1K = 99 ; // Trebia SNP 1000 processor +constexpr Elf_Half EM_ST200 = 100; // STMicroelectronics ST200 microcontroller +constexpr Elf_Half EM_IP2K = 101; // Ubicom IP2022 micro controller +constexpr Elf_Half EM_MAX = 102; // MAX Processor +constexpr Elf_Half EM_CR = 103; // National Semiconductor CompactRISC +constexpr Elf_Half EM_F2MC16 = 104; // Fujitsu F2MC16 +constexpr Elf_Half EM_MSP430 = 105; // TI msp430 micro controller +constexpr Elf_Half EM_BLACKFIN = 106; // ADI Blackfin +constexpr Elf_Half EM_SE_C33 = 107; // S1C33 Family of Seiko Epson processors +constexpr Elf_Half EM_SEP = 108; // Sharp embedded microprocessor +constexpr Elf_Half EM_ARCA = 109; // Arca RISC Microprocessor +constexpr Elf_Half EM_UNICORE = 110; // Microprocessor series from PKU-Unity Ltd. +constexpr Elf_Half EM_EXCESS = 111; // eXcess: 16/32/64-bit configurable embedded CPU +constexpr Elf_Half EM_DXP = 112; // Icera Semiconductor Inc. Deep Execution Processor +constexpr Elf_Half EM_ALTERA_NIOS2 = 113; // Altera Nios II soft-core processor +constexpr Elf_Half EM_CRX = 114; // National Semiconductor CRX +constexpr Elf_Half EM_XGATE = 115; // Motorola XGATE embedded processor +constexpr Elf_Half EM_C166 = 116; // Infineon C16x/XC16x processor +constexpr Elf_Half EM_M16C = 117; // Renesas M16C series microprocessors +constexpr Elf_Half EM_DSPIC30F = 118; // Microchip Technology dsPIC30F DSignal Controller +constexpr Elf_Half EM_CE = 119; // Freescale Communication Engine RISC core +constexpr Elf_Half EM_M32C = 120; // Renesas M32C series microprocessors +constexpr Elf_Half EM_res121 = 121; // Reserved +constexpr Elf_Half EM_res122 = 122; // Reserved +constexpr Elf_Half EM_res123 = 123; // Reserved +constexpr Elf_Half EM_res124 = 124; // Reserved +constexpr Elf_Half EM_res125 = 125; // Reserved +constexpr Elf_Half EM_res126 = 126; // Reserved +constexpr Elf_Half EM_res127 = 127; // Reserved +constexpr Elf_Half EM_res128 = 128; // Reserved +constexpr Elf_Half EM_res129 = 129; // Reserved +constexpr Elf_Half EM_res130 = 130; // Reserved +constexpr Elf_Half EM_TSK3000 = 131; // Altium TSK3000 core +constexpr Elf_Half EM_RS08 = 132; // Freescale RS08 embedded processor +constexpr Elf_Half EM_res133 = 133; // Reserved +constexpr Elf_Half EM_ECOG2 = 134; // Cyan Technology eCOG2 microprocessor +constexpr Elf_Half EM_SCORE = 135; // Sunplus Score +constexpr Elf_Half EM_SCORE7 = 135; // Sunplus S+core7 RISC processor +constexpr Elf_Half EM_DSP24 = 136; // New Japan Radio (NJR) 24-bit DSP Processor +constexpr Elf_Half EM_VIDEOCORE3 = 137; // Broadcom VideoCore III processor +constexpr Elf_Half EM_LATTICEMICO32 = 138; // RISC processor for Lattice FPGA architecture +constexpr Elf_Half EM_SE_C17 = 139; // Seiko Epson C17 family +constexpr Elf_Half EM_TI_C6000 = 140; // Texas Instruments TMS320C6000 DSP family +constexpr Elf_Half EM_TI_C2000 = 141; // Texas Instruments TMS320C2000 DSP family +constexpr Elf_Half EM_TI_C5500 = 142; // Texas Instruments TMS320C55x DSP family +constexpr Elf_Half EM_res143 = 143; // Reserved +constexpr Elf_Half EM_res144 = 144; // Reserved +constexpr Elf_Half EM_res145 = 145; // Reserved +constexpr Elf_Half EM_res146 = 146; // Reserved +constexpr Elf_Half EM_res147 = 147; // Reserved +constexpr Elf_Half EM_res148 = 148; // Reserved +constexpr Elf_Half EM_res149 = 149; // Reserved +constexpr Elf_Half EM_res150 = 150; // Reserved +constexpr Elf_Half EM_res151 = 151; // Reserved +constexpr Elf_Half EM_res152 = 152; // Reserved +constexpr Elf_Half EM_res153 = 153; // Reserved +constexpr Elf_Half EM_res154 = 154; // Reserved +constexpr Elf_Half EM_res155 = 155; // Reserved +constexpr Elf_Half EM_res156 = 156; // Reserved +constexpr Elf_Half EM_res157 = 157; // Reserved +constexpr Elf_Half EM_res158 = 158; // Reserved +constexpr Elf_Half EM_res159 = 159; // Reserved +constexpr Elf_Half EM_MMDSP_PLUS = 160; // STMicroelectronics 64bit VLIW Data Signal Processor +constexpr Elf_Half EM_CYPRESS_M8C = 161; // Cypress M8C microprocessor +constexpr Elf_Half EM_R32C = 162; // Renesas R32C series microprocessors +constexpr Elf_Half EM_TRIMEDIA = 163; // NXP Semiconductors TriMedia architecture family +constexpr Elf_Half EM_QDSP6 = 164; // QUALCOMM DSP6 Processor +constexpr Elf_Half EM_8051 = 165; // Intel 8051 and variants +constexpr Elf_Half EM_STXP7X = 166; // STMicroelectronics STxP7x family +constexpr Elf_Half EM_NDS32 = 167; // Andes Technology embedded RISC processor family +constexpr Elf_Half EM_ECOG1 = 168; // Cyan Technology eCOG1X family +constexpr Elf_Half EM_ECOG1X = 168; // Cyan Technology eCOG1X family +constexpr Elf_Half EM_MAXQ30 = 169; // Dallas Semiconductor MAXQ30 Core Micro-controllers +constexpr Elf_Half EM_XIMO16 = 170; // New Japan Radio (NJR) 16-bit DSP Processor +constexpr Elf_Half EM_MANIK = 171; // M2000 Reconfigurable RISC Microprocessor +constexpr Elf_Half EM_CRAYNV2 = 172; // Cray Inc. NV2 vector architecture +constexpr Elf_Half EM_RX = 173; // Renesas RX family +constexpr Elf_Half EM_METAG = 174; // Imagination Technologies META processor architecture +constexpr Elf_Half EM_MCST_ELBRUS = 175; // MCST Elbrus general purpose hardware architecture +constexpr Elf_Half EM_ECOG16 = 176; // Cyan Technology eCOG16 family +constexpr Elf_Half EM_CR16 = 177; // National Semiconductor CompactRISC 16-bit processor +constexpr Elf_Half EM_ETPU = 178; // Freescale Extended Time Processing Unit +constexpr Elf_Half EM_SLE9X = 179; // Infineon Technologies SLE9X core +constexpr Elf_Half EM_L1OM = 180; // Intel L1OM +constexpr Elf_Half EM_INTEL181 = 181; // Reserved by Intel +constexpr Elf_Half EM_INTEL182 = 182; // Reserved by Intel +constexpr Elf_Half EM_AARCH64 = 183; // ARM AArch64 +constexpr Elf_Half EM_res184 = 184; // Reserved by ARM +constexpr Elf_Half EM_AVR32 = 185; // Atmel Corporation 32-bit microprocessor family +constexpr Elf_Half EM_STM8 = 186; // STMicroeletronics STM8 8-bit microcontroller +constexpr Elf_Half EM_TILE64 = 187; // Tilera TILE64 multicore architecture family +constexpr Elf_Half EM_TILEPRO = 188; // Tilera TILEPro multicore architecture family +constexpr Elf_Half EM_MICROBLAZE = 189; // Xilinx MicroBlaze 32-bit RISC soft processor core +constexpr Elf_Half EM_CUDA = 190; // NVIDIA CUDA architecture +constexpr Elf_Half EM_TILEGX = 191; // Tilera TILE-Gx multicore architecture family +constexpr Elf_Half EM_CLOUDSHIELD = 192; // CloudShield architecture family +constexpr Elf_Half EM_COREA_1ST = 193; // KIPO-KAIST Core-A 1st generation processor family +constexpr Elf_Half EM_COREA_2ND = 194; // KIPO-KAIST Core-A 2nd generation processor family +constexpr Elf_Half EM_ARC_COMPACT2 = 195; // Synopsys ARCompact V2 +constexpr Elf_Half EM_OPEN8 = 196; // Open8 8-bit RISC soft processor core +constexpr Elf_Half EM_RL78 = 197; // Renesas RL78 family +constexpr Elf_Half EM_VIDEOCORE5 = 198; // Broadcom VideoCore V processor +constexpr Elf_Half EM_78KOR = 199; // Renesas 78KOR family +constexpr Elf_Half EM_56800EX = 200; // Freescale 56800EX Digital Signal Controller (DSC) +constexpr Elf_Half EM_BA1 = 201; // Beyond BA1 CPU architecture +constexpr Elf_Half EM_BA2 = 202; // Beyond BA2 CPU architecture +constexpr Elf_Half EM_XCORE = 203; // XMOS xCORE processor family +constexpr Elf_Half EM_MCHP_PIC = 204; // Microchip 8-bit PIC(r) family +constexpr Elf_Half EM_INTEL205 = 205; // Reserved by Intel +constexpr Elf_Half EM_INTEL206 = 206; // Reserved by Intel +constexpr Elf_Half EM_INTEL207 = 207; // Reserved by Intel +constexpr Elf_Half EM_INTEL208 = 208; // Reserved by Intel +constexpr Elf_Half EM_INTEL209 = 209; // Reserved by Intel +constexpr Elf_Half EM_KM32 = 210; // KM211 KM32 32-bit processor +constexpr Elf_Half EM_KMX32 = 211; // KM211 KMX32 32-bit processor +constexpr Elf_Half EM_KMX16 = 212; // KM211 KMX16 16-bit processor +constexpr Elf_Half EM_KMX8 = 213; // KM211 KMX8 8-bit processor +constexpr Elf_Half EM_KVARC = 214; // KM211 KVARC processor +constexpr Elf_Half EM_CDP = 215; // Paneve CDP architecture family +constexpr Elf_Half EM_COGE = 216; // Cognitive Smart Memory Processor +constexpr Elf_Half EM_COOL = 217; // iCelero CoolEngine +constexpr Elf_Half EM_NORC = 218; // Nanoradio Optimized RISC +constexpr Elf_Half EM_CSR_KALIMBA = 219; // CSR Kalimba architecture family +constexpr Elf_Half EM_Z80 = 220; // Zilog Z80 +constexpr Elf_Half EM_VISIUM = 221; // Controls and Data Services VISIUMcore processor +constexpr Elf_Half EM_FT32 = 222; // FTDI Chip FT32 high performance 32-bit RISC architecture +constexpr Elf_Half EM_MOXIE = 223; // Moxie processor family +constexpr Elf_Half EM_AMDGPU = 224; // AMD GPU architecture +constexpr Elf_Half EM_RISCV = 243; // RISC-V +constexpr Elf_Half EM_LANAI = 244; // Lanai processor +constexpr Elf_Half EM_CEVA = 245; // CEVA Processor Architecture Family +constexpr Elf_Half EM_CEVA_X2 = 246; // CEVA X2 Processor Family +constexpr Elf_Half EM_BPF = 247; // Linux BPF – in-kernel virtual machine +constexpr Elf_Half EM_GRAPHCORE_IPU = 248; // Graphcore Intelligent Processing Unit +constexpr Elf_Half EM_IMG1 = 249; // Imagination Technologies +constexpr Elf_Half EM_NFP = 250; // Netronome Flow Processor (P) +constexpr Elf_Half EM_CSKY = 252; // C-SKY processor family +constexpr Elf_Half EM_ARC_COMPACT3_64 = 253; // "Synopsys ARCv2.3 64-bit"; +constexpr Elf_Half EM_MCS6502 = 254; // "MOS Technology MCS 6502 processor"; +constexpr Elf_Half EM_ARC_COMPACT3 = 255; // "Synopsys ARCv2.3 32-bit"; +constexpr Elf_Half EM_KVX = 256; // "Kalray VLIW core of the MPPA processor family"; +constexpr Elf_Half EM_65816 = 257; // "WDC 65816/65C816"; +constexpr Elf_Half EM_LOONGARCH = 258; // "Loongson Loongarch"; +constexpr Elf_Half EM_KF32 = 259; // "ChipON KungFu32"; + +constexpr Elf_Half EM_MT = 0x2530; // "Morpho Techologies MT processor"; +constexpr Elf_Half EM_ALPHA = 0x9026; // "Alpha"; +constexpr Elf_Half EM_WEBASSEMBLY = 0x4157; // "Web Assembly"; +constexpr Elf_Half EM_DLX = 0x5aa5; // "OpenDLX"; +constexpr Elf_Half EM_XSTORMY16 = 0xad45; // "Sanyo XStormy16 CPU core"; +constexpr Elf_Half EM_IQ2000 = 0xFEBA; // "Vitesse IQ2000"; +constexpr Elf_Half EM_M32C_OLD = 0xFEB; +constexpr Elf_Half EM_NIOS32 = 0xFEBB; // "Altera Nios"; +constexpr Elf_Half EM_CYGNUS_MEP = 0xF00D; // "Toshiba MeP Media Engine"; +constexpr Elf_Half EM_ADAPTEVA_EPIPHANY = 0x1223; // "Adapteva EPIPHANY"; +constexpr Elf_Half EM_CYGNUS_FRV = 0x5441; // "Fujitsu FR-V"; +constexpr Elf_Half EM_S12Z = 0x4DEF; // "Freescale S12Z"; +// clang-format on + +// File version +constexpr unsigned char EV_NONE = 0; +constexpr unsigned char EV_CURRENT = 1; + +// Identification index +constexpr unsigned char EI_MAG0 = 0; +constexpr unsigned char EI_MAG1 = 1; +constexpr unsigned char EI_MAG2 = 2; +constexpr unsigned char EI_MAG3 = 3; +constexpr unsigned char EI_CLASS = 4; +constexpr unsigned char EI_DATA = 5; +constexpr unsigned char EI_VERSION = 6; +constexpr unsigned char EI_OSABI = 7; +constexpr unsigned char EI_ABIVERSION = 8; +constexpr unsigned char EI_PAD = 9; +constexpr unsigned char EI_NIDENT = 16; + +// Magic number +constexpr unsigned char ELFMAG0 = 0x7F; +constexpr unsigned char ELFMAG1 = 'E'; +constexpr unsigned char ELFMAG2 = 'L'; +constexpr unsigned char ELFMAG3 = 'F'; + +// File class +constexpr unsigned char ELFCLASSNONE = 0; +constexpr unsigned char ELFCLASS32 = 1; +constexpr unsigned char ELFCLASS64 = 2; + +// Encoding +constexpr unsigned char ELFDATANONE = 0; +constexpr unsigned char ELFDATA2LSB = 1; +constexpr unsigned char ELFDATA2MSB = 2; + +// clang-format off +// OS extensions +constexpr unsigned char ELFOSABI_NONE = 0; // No extensions or unspecified +constexpr unsigned char ELFOSABI_HPUX = 1; // Hewlett-Packard HP-UX +constexpr unsigned char ELFOSABI_NETBSD = 2; // NetBSD +constexpr unsigned char ELFOSABI_LINUX = 3; // Linux +constexpr unsigned char ELFOSABI_SOLARIS = 6; // Sun Solaris +constexpr unsigned char ELFOSABI_AIX = 7; // AIX +constexpr unsigned char ELFOSABI_IRIX = 8; // IRIX +constexpr unsigned char ELFOSABI_FREEBSD = 9; // FreeBSD +constexpr unsigned char ELFOSABI_TRU64 = 10; // Compaq TRU64 UNIX +constexpr unsigned char ELFOSABI_MODESTO = 11; // Novell Modesto +constexpr unsigned char ELFOSABI_OPENBSD = 12; // Open BSD +constexpr unsigned char ELFOSABI_OPENVMS = 13; // Open VMS +constexpr unsigned char ELFOSABI_NSK = 14; // Hewlett-Packard Non-Stop Kernel +constexpr unsigned char ELFOSABI_AROS = 15; // Amiga Research OS +constexpr unsigned char ELFOSABI_FENIXOS = 16; // The FenixOS highly scalable multi-core OS + +// 64-255 Architecture-specific value range +// AMDGPU OS for HSA compatible compute kernels +constexpr unsigned char ELFOSABI_AMDGPU_HSA = 64; +// AMDGPU OS for AMD PAL compatible graphics +// shaders and compute kernels +constexpr unsigned char ELFOSABI_AMDGPU_PAL = 65; +// AMDGPU OS for Mesa3D compatible graphics +// shaders and compute kernels +constexpr unsigned char ELFOSABI_AMDGPU_MESA3D = 66; +// clang-format on + +constexpr unsigned char ELFABIVERSION_AMDGPU_HSA_V2 = 0; +constexpr unsigned char ELFABIVERSION_AMDGPU_HSA_V3 = 1; +constexpr unsigned char ELFABIVERSION_AMDGPU_HSA_V4 = 2; + +// AMDGPU specific e_flags +constexpr Elf_Word EF_AMDGPU_MACH = 0x0ff; // AMDGPU processor selection mask. +// Indicates if the XNACK target feature is +// enabled for all code contained in the ELF. +constexpr Elf_Word EF_AMDGPU_XNACK = 0x100; + +constexpr Elf_Word EF_AMDGPU_FEATURE_XNACK_V2 = 0x01; +constexpr Elf_Word EF_AMDGPU_FEATURE_TRAP_HANDLER_V2 = 0x02; +constexpr Elf_Word EF_AMDGPU_FEATURE_XNACK_V3 = 0x100; +constexpr Elf_Word EF_AMDGPU_FEATURE_SRAMECC_V3 = 0x200; +constexpr Elf_Word EF_AMDGPU_FEATURE_XNACK_V4 = 0x300; +constexpr Elf_Word EF_AMDGPU_FEATURE_XNACK_UNSUPPORTED_V4 = 0x000; +constexpr Elf_Word EF_AMDGPU_FEATURE_XNACK_ANY_V4 = 0x100; +constexpr Elf_Word EF_AMDGPU_FEATURE_XNACK_OFF_V4 = 0x200; +constexpr Elf_Word EF_AMDGPU_FEATURE_XNACK_ON_V4 = 0x300; +constexpr Elf_Word EF_AMDGPU_FEATURE_SRAMECC_V4 = 0xc00; +constexpr Elf_Word EF_AMDGPU_FEATURE_SRAMECC_UNSUPPORTED_V4 = 0x000; +constexpr Elf_Word EF_AMDGPU_FEATURE_SRAMECC_ANY_V4 = 0x400; +constexpr Elf_Word EF_AMDGPU_FEATURE_SRAMECC_OFF_V4 = 0x800; +constexpr Elf_Word EF_AMDGPU_FEATURE_SRAMECC_ON_V4 = 0xc00; + +// AMDGPU processors +constexpr Elf_Word EF_AMDGPU_MACH_NONE = 0x000; // Unspecified processor. +constexpr Elf_Word EF_AMDGPU_MACH_R600_R600 = 0x001; +constexpr Elf_Word EF_AMDGPU_MACH_R600_R630 = 0x002; +constexpr Elf_Word EF_AMDGPU_MACH_R600_RS880 = 0x003; +constexpr Elf_Word EF_AMDGPU_MACH_R600_RV670 = 0x004; +constexpr Elf_Word EF_AMDGPU_MACH_R600_RV710 = 0x005; +constexpr Elf_Word EF_AMDGPU_MACH_R600_RV730 = 0x006; +constexpr Elf_Word EF_AMDGPU_MACH_R600_RV770 = 0x007; +constexpr Elf_Word EF_AMDGPU_MACH_R600_CEDAR = 0x008; +constexpr Elf_Word EF_AMDGPU_MACH_R600_CYPRESS = 0x009; +constexpr Elf_Word EF_AMDGPU_MACH_R600_JUNIPER = 0x00a; +constexpr Elf_Word EF_AMDGPU_MACH_R600_REDWOOD = 0x00b; +constexpr Elf_Word EF_AMDGPU_MACH_R600_SUMO = 0x00c; +constexpr Elf_Word EF_AMDGPU_MACH_R600_BARTS = 0x00d; +constexpr Elf_Word EF_AMDGPU_MACH_R600_CAICOS = 0x00e; +constexpr Elf_Word EF_AMDGPU_MACH_R600_CAYMAN = 0x00f; +constexpr Elf_Word EF_AMDGPU_MACH_R600_TURKS = 0x010; +constexpr Elf_Word EF_AMDGPU_MACH_R600_RESERVED_FIRST = 0x011; +constexpr Elf_Word EF_AMDGPU_MACH_R600_RESERVED_LAST = 0x01f; +constexpr Elf_Word EF_AMDGPU_MACH_R600_FIRST = EF_AMDGPU_MACH_R600_R600; +constexpr Elf_Word EF_AMDGPU_MACH_R600_LAST = EF_AMDGPU_MACH_R600_TURKS; + +// AMDGCN-based processors. +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX600 = 0x020; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX601 = 0x021; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX700 = 0x022; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX701 = 0x023; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX702 = 0x024; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX703 = 0x025; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX704 = 0x026; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_RESERVED_0X27 = 0x027; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX801 = 0x028; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX802 = 0x029; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX803 = 0x02a; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX810 = 0x02b; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX900 = 0x02c; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX902 = 0x02d; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX904 = 0x02e; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX906 = 0x02f; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX908 = 0x030; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX909 = 0x031; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX90C = 0x032; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX1010 = 0x033; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX1011 = 0x034; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX1012 = 0x035; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX1030 = 0x036; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX1031 = 0x037; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX1032 = 0x038; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX1033 = 0x039; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX602 = 0x03a; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX705 = 0x03b; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX805 = 0x03c; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_RESERVED_0X3D = 0x03d; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX1034 = 0x03e; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX90A = 0x03f; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_RESERVED_0X40 = 0x040; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_RESERVED_0X41 = 0x041; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_GFX1013 = 0x042; +// First/last AMDGCN-based processors. +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_FIRST = EF_AMDGPU_MACH_AMDGCN_GFX600; +constexpr Elf_Word EF_AMDGPU_MACH_AMDGCN_LAST = EF_AMDGPU_MACH_AMDGCN_GFX1013; + +///////////////////// +// Sections constants + +// Section indexes +constexpr Elf_Word SHN_UNDEF = 0; +constexpr Elf_Word SHN_LORESERVE = 0xFF00; +constexpr Elf_Word SHN_LOPROC = 0xFF00; +constexpr Elf_Word SHN_HIPROC = 0xFF1F; +constexpr Elf_Word SHN_LOOS = 0xFF20; +constexpr Elf_Word SHN_HIOS = 0xFF3F; +constexpr Elf_Word SHN_ABS = 0xFFF1; +constexpr Elf_Word SHN_COMMON = 0xFFF2; +constexpr Elf_Word SHN_XINDEX = 0xFFFF; +constexpr Elf_Word SHN_HIRESERVE = 0xFFFF; + +// Section types +constexpr Elf_Word SHT_NULL = 0; +constexpr Elf_Word SHT_PROGBITS = 1; +constexpr Elf_Word SHT_SYMTAB = 2; +constexpr Elf_Word SHT_STRTAB = 3; +constexpr Elf_Word SHT_RELA = 4; +constexpr Elf_Word SHT_HASH = 5; +constexpr Elf_Word SHT_DYNAMIC = 6; +constexpr Elf_Word SHT_NOTE = 7; +constexpr Elf_Word SHT_NOBITS = 8; +constexpr Elf_Word SHT_REL = 9; +constexpr Elf_Word SHT_SHLIB = 10; +constexpr Elf_Word SHT_DYNSYM = 11; +constexpr Elf_Word SHT_INIT_ARRAY = 14; +constexpr Elf_Word SHT_FINI_ARRAY = 15; +constexpr Elf_Word SHT_PREINIT_ARRAY = 16; +constexpr Elf_Word SHT_GROUP = 17; +constexpr Elf_Word SHT_SYMTAB_SHNDX = 18; +constexpr Elf_Word SHT_GNU_ATTRIBUTES = 0x6ffffff5; +constexpr Elf_Word SHT_GNU_HASH = 0x6ffffff6; +constexpr Elf_Word SHT_GNU_LIBLIST = 0x6ffffff7; +constexpr Elf_Word SHT_CHECKSUM = 0x6ffffff8; +constexpr Elf_Word SHT_LOSUNW = 0x6ffffffa; +constexpr Elf_Word SHT_SUNW_move = 0x6ffffffa; +constexpr Elf_Word SHT_SUNW_COMDAT = 0x6ffffffb; +constexpr Elf_Word SHT_SUNW_syminfo = 0x6ffffffc; +constexpr Elf_Word SHT_GNU_verdef = 0x6ffffffd; +constexpr Elf_Word SHT_GNU_verneed = 0x6ffffffe; +constexpr Elf_Word SHT_GNU_versym = 0x6fffffff; +constexpr Elf_Word SHT_LOOS = 0x60000000; +constexpr Elf_Word SHT_HIOS = 0x6fffffff; +constexpr Elf_Word SHT_LOPROC = 0x70000000; +constexpr Elf_Word SHT_HIPROC = 0x7FFFFFFF; +constexpr Elf_Word SHT_LOUSER = 0x80000000; +constexpr Elf_Word SHT_HIUSER = 0xFFFFFFFF; + +// Section attribute flags +constexpr Elf_Xword SHF_WRITE = 0x1; +constexpr Elf_Xword SHF_ALLOC = 0x2; +constexpr Elf_Xword SHF_EXECINSTR = 0x4; +constexpr Elf_Xword SHF_MERGE = 0x10; +constexpr Elf_Xword SHF_STRINGS = 0x20; +constexpr Elf_Xword SHF_INFO_LINK = 0x40; +constexpr Elf_Xword SHF_LINK_ORDER = 0x80; +constexpr Elf_Xword SHF_OS_NONCONFORMING = 0x100; +constexpr Elf_Xword SHF_GROUP = 0x200; +constexpr Elf_Xword SHF_TLS = 0x400; +constexpr Elf_Xword SHF_MASKOS = 0x0ff00000; +constexpr Elf_Xword SHF_MASKPROC = 0xF0000000; + +// Section group flags +constexpr Elf_Word GRP_COMDAT = 0x1; +constexpr Elf_Word GRP_MASKOS = 0x0ff00000; +constexpr Elf_Word GRP_MASKPROC = 0xf0000000; + +// Symbol binding +constexpr unsigned char STB_LOCAL = 0; +constexpr unsigned char STB_GLOBAL = 1; +constexpr unsigned char STB_WEAK = 2; +constexpr unsigned char STB_LOOS = 10; +constexpr unsigned char STB_HIOS = 12; +constexpr unsigned char STB_MULTIDEF = 13; +constexpr unsigned char STB_LOPROC = 13; +constexpr unsigned char STB_HIPROC = 15; + +// Values of note segment descriptor types for core files +constexpr Elf_Word NT_PRSTATUS = 1; // Contains copy of prstatus struct +constexpr Elf_Word NT_FPREGSET = 2; // Contains copy of fpregset struct +constexpr Elf_Word NT_PRPSINFO = 3; // Contains copy of prpsinfo struct +constexpr Elf_Word NT_TASKSTRUCT = 4; // Contains copy of task struct +constexpr Elf_Word NT_AUXV = 6; // Contains copy of Elfxx_auxv_t +constexpr Elf_Word NT_SIGINFO = 0x53494749; // Fields of siginfo_t. +constexpr Elf_Word NT_FILE = 0x46494c45; // Description of mapped files. + +// Note segments for core files on dir-style procfs systems. +constexpr Elf_Word NT_PSTATUS = 10; // Has a struct pstatus +constexpr Elf_Word NT_FPREGS = 12; // Has a struct fpregset +constexpr Elf_Word NT_PSINFO = 13; // Has a struct psinfo +constexpr Elf_Word NT_LWPSTATUS = 16; // Has a struct lwpstatus_t +constexpr Elf_Word NT_LWPSINFO = 17; // Has a struct lwpsinfo_t +constexpr Elf_Word NT_WIN32PSTATUS = 18; // Has a struct win32_pstatus + +// clang-format off + +// Note name must be "LINUX" +constexpr Elf_Word NT_PRXFPREG = 0x46e62b7f; // Contains a user_xfpregs_struct; +constexpr Elf_Word NT_PPC_VMX = 0x100; // PowerPC Altivec/VMX registers +constexpr Elf_Word NT_PPC_VSX = 0x102; // PowerPC VSX registers +constexpr Elf_Word NT_PPC_TAR = 0x103; // PowerPC Target Address Register +constexpr Elf_Word NT_PPC_PPR = 0x104; // PowerPC Program Priority Register +constexpr Elf_Word NT_PPC_DSCR = 0x105; // PowerPC Data Stream Control Register +constexpr Elf_Word NT_PPC_EBB = 0x106; // PowerPC Event Based Branch Registers +constexpr Elf_Word NT_PPC_PMU = 0x107; // PowerPC Performance Monitor Registers +constexpr Elf_Word NT_PPC_TM_CGPR = 0x108; // PowerPC TM checkpointed GPR Registers +constexpr Elf_Word NT_PPC_TM_CFPR = 0x109; // PowerPC TM checkpointed FPR Registers +constexpr Elf_Word NT_PPC_TM_CVMX = 0x10a; // PowerPC TM checkpointed VMX Registers +constexpr Elf_Word NT_PPC_TM_CVSX = 0x10b; // PowerPC TM checkpointed VSX Registers +constexpr Elf_Word NT_PPC_TM_SPR = 0x10c; // PowerPC TM Special Purpose Registers +constexpr Elf_Word NT_PPC_TM_CTAR = 0x10d; // PowerPC TM checkpointed TAR +constexpr Elf_Word NT_PPC_TM_CPPR = 0x10e; // PowerPC TM checkpointed PPR +constexpr Elf_Word NT_PPC_TM_CDSCR = 0x10f; // PowerPC TM checkpointed Data SCR +constexpr Elf_Word NT_386_TLS = 0x200; // x86 TLS information +constexpr Elf_Word NT_386_IOPERM = 0x201; // x86 io permissions +constexpr Elf_Word NT_X86_XSTATE = 0x202; // x86 XSAVE extended state +constexpr Elf_Word NT_X86_CET = 0x203; // x86 CET state. +constexpr Elf_Word NT_S390_HIGH_GPRS = 0x300; // S/390 upper halves of GPRs +constexpr Elf_Word NT_S390_TIMER = 0x301; // S390 timer +constexpr Elf_Word NT_S390_TODCMP = 0x302; // S390 TOD clock comparator +constexpr Elf_Word NT_S390_TODPREG = 0x303; // S390 TOD programmable register +constexpr Elf_Word NT_S390_CTRS = 0x304; // S390 control registers +constexpr Elf_Word NT_S390_PREFIX = 0x305; // S390 prefix register +constexpr Elf_Word NT_S390_LAST_BREAK = 0x306; // S390 breaking event address +constexpr Elf_Word NT_S390_SYSTEM_CALL = 0x307; // S390 system call restart data +constexpr Elf_Word NT_S390_TDB = 0x308; // S390 transaction diagnostic block +constexpr Elf_Word NT_S390_VXRS_LOW = 0x309; // S390 vector registers 0-15 upper half +constexpr Elf_Word NT_S390_VXRS_HIGH = 0x30a; // S390 vector registers 16-31 +constexpr Elf_Word NT_S390_GS_CB = 0x30b; // s390 guarded storage registers +constexpr Elf_Word NT_S390_GS_BC = 0x30c; // s390 guarded storage broadcast control block +constexpr Elf_Word NT_ARM_VFP = 0x400; // ARM VFP registers +constexpr Elf_Word NT_ARM_TLS = 0x401; // AArch TLS registers +constexpr Elf_Word NT_ARM_HW_BREAK = 0x402; // AArch hardware breakpoint registers +constexpr Elf_Word NT_ARM_HW_WATCH = 0x403; // AArch hardware watchpoint registers +constexpr Elf_Word NT_ARM_SVE = 0x405; // AArch SVE registers. +constexpr Elf_Word NT_ARM_PAC_MASK = 0x406; // AArch pointer authentication code masks +constexpr Elf_Word NT_ARM_PACA_KEYS = 0x407; // ARM pointer authentication address keys +constexpr Elf_Word NT_ARM_PACG_KEYS = 0x408; // ARM pointer authentication generic keys +constexpr Elf_Word NT_ARM_TAGGED_ADDR_CTRL = 0x409; // AArch64 tagged address control (prctl()) +constexpr Elf_Word NT_ARM_PAC_ENABLED_KEYS = 0x40a; // AArch64 pointer authentication enabled keys (prctl()) +constexpr Elf_Word NT_ARC_V2 = 0x600; // ARC HS accumulator/extra registers. +constexpr Elf_Word NT_LARCH_CPUCFG = 0xa00; // LoongArch CPU config registers +constexpr Elf_Word NT_LARCH_CSR = 0xa01; // LoongArch Control State Registers +constexpr Elf_Word NT_LARCH_LSX = 0xa02; // LoongArch SIMD eXtension registers +constexpr Elf_Word NT_LARCH_LASX = 0xa03; // LoongArch Advanced SIMD eXtension registers +constexpr Elf_Word NT_RISCV_CSR = 0x900; // RISC-V Control and Status Registers + +// Note name must be "CORE" +constexpr Elf_Word NT_LARCH_LBT = 0xa04; // LoongArch Binary Translation registers + +/* The range 0xff000000 to 0xffffffff is set aside for notes that don't + originate from any particular operating system. */ +constexpr Elf_Word NT_GDB_TDESC = 0xff000000; // Contains copy of GDB's target description XML. +constexpr Elf_Word NT_MEMTAG = 0xff000001; // Contains a copy of the memory tags. +/* ARM-specific NT_MEMTAG types. */ +constexpr Elf_Word NT_MEMTAG_TYPE_AARCH_MTE = 0x400; // MTE memory tags for AArch64. + +/* Note segment for SystemTap probes. */ +#define NT_STAPSDT 3 + +// Note name is "FreeBSD" +constexpr Elf_Word NT_FREEBSD_THRMISC = 7; // Thread miscellaneous info. +constexpr Elf_Word NT_FREEBSD_PROCSTAT_PROC = 8; // Procstat proc data. +constexpr Elf_Word NT_FREEBSD_PROCSTAT_FILES = 9; // Procstat files data. +constexpr Elf_Word NT_FREEBSD_PROCSTAT_VMMAP = 10; // Procstat vmmap data. +constexpr Elf_Word NT_FREEBSD_PROCSTAT_GROUPS = 11; // Procstat groups data. +constexpr Elf_Word NT_FREEBSD_PROCSTAT_UMASK = 12; // Procstat umask data. +constexpr Elf_Word NT_FREEBSD_PROCSTAT_RLIMIT = 13; // Procstat rlimit data. +constexpr Elf_Word NT_FREEBSD_PROCSTAT_OSREL = 14; // Procstat osreldate data. +constexpr Elf_Word NT_FREEBSD_PROCSTAT_PSSTRINGS = 15; // Procstat ps_strings data. +constexpr Elf_Word NT_FREEBSD_PROCSTAT_AUXV = 16; // Procstat auxv data. +constexpr Elf_Word NT_FREEBSD_PTLWPINFO = 17; // Thread ptrace miscellaneous info. + +// Note name must start with "NetBSD-CORE" +constexpr Elf_Word NT_NETBSDCORE_PROCINFO = 1; // Has a struct procinfo +constexpr Elf_Word NT_NETBSDCORE_AUXV = 2; // Has auxv data +constexpr Elf_Word NT_NETBSDCORE_LWPSTATUS = 24; // Has LWPSTATUS data +constexpr Elf_Word NT_NETBSDCORE_FIRSTMACH = 32; // start of machdep note types + +// Note name is "OpenBSD" +constexpr Elf_Word NT_OPENBSD_PROCINFO = 10; +constexpr Elf_Word NT_OPENBSD_AUXV = 11; +constexpr Elf_Word NT_OPENBSD_REGS = 20; +constexpr Elf_Word NT_OPENBSD_FPREGS = 21; +constexpr Elf_Word NT_OPENBSD_XFPREGS = 22; +constexpr Elf_Word NT_OPENBSD_WCOOKIE = 23; + +// Note name must start with "SPU" +constexpr Elf_Word NT_SPU = 1; + +// Values of note segment descriptor types for object files +constexpr Elf_Word NT_VERSION = 1; // Contains a version string. +constexpr Elf_Word NT_ARCH = 2; // Contains an architecture string. +constexpr Elf_Word NT_GO_BUILDID = 4; // Contains GO buildid data. + +// Values for notes in non-core files using name "GNU" +constexpr Elf_Word NT_GNU_ABI_TAG = 1; +constexpr Elf_Word NT_GNU_HWCAP = 2; // Used by ld.so and kernel vDSO. +constexpr Elf_Word NT_GNU_BUILD_ID = 3; // Generated by ld --build-id. +constexpr Elf_Word NT_GNU_GOLD_VERSION = 4; // Generated by gold. +constexpr Elf_Word NT_GNU_PROPERTY_TYPE_0 = 5; // Generated by gcc. +// clang-format on + +constexpr Elf_Word NT_GNU_BUILD_ATTRIBUTE_OPEN = 0x100; +constexpr Elf_Word NT_GNU_BUILD_ATTRIBUTE_FUNC = 0x101; + +// Symbol types +constexpr Elf_Word STT_NOTYPE = 0; +constexpr Elf_Word STT_OBJECT = 1; +constexpr Elf_Word STT_FUNC = 2; +constexpr Elf_Word STT_SECTION = 3; +constexpr Elf_Word STT_FILE = 4; +constexpr Elf_Word STT_COMMON = 5; +constexpr Elf_Word STT_TLS = 6; +constexpr Elf_Word STT_LOOS = 10; +constexpr Elf_Word STT_AMDGPU_HSA_KERNEL = 10; +constexpr Elf_Word STT_HIOS = 12; +constexpr Elf_Word STT_LOPROC = 13; +constexpr Elf_Word STT_HIPROC = 15; + +// Symbol visibility +constexpr unsigned char STV_DEFAULT = 0; +constexpr unsigned char STV_INTERNAL = 1; +constexpr unsigned char STV_HIDDEN = 2; +constexpr unsigned char STV_PROTECTED = 3; + +// Undefined name +constexpr Elf_Word STN_UNDEF = 0; + +// Relocation types +constexpr unsigned char R_386_NONE = 0; +constexpr unsigned char R_X86_64_NONE = 0; +constexpr unsigned char R_AMDGPU_NONE = 0; +constexpr unsigned char R_386_32 = 1; +constexpr unsigned char R_X86_64_64 = 1; +constexpr unsigned char R_AMDGPU_ABS32_LO = 1; +constexpr unsigned char R_386_PC32 = 2; +constexpr unsigned char R_X86_64_PC32 = 2; +constexpr unsigned char R_AMDGPU_ABS32_HI = 2; +constexpr unsigned char R_386_GOT32 = 3; +constexpr unsigned char R_X86_64_GOT32 = 3; +constexpr unsigned char R_AMDGPU_ABS64 = 3; +constexpr unsigned char R_386_PLT32 = 4; +constexpr unsigned char R_X86_64_PLT32 = 4; +constexpr unsigned char R_AMDGPU_REL32 = 4; +constexpr unsigned char R_386_COPY = 5; +constexpr unsigned char R_X86_64_COPY = 5; +constexpr unsigned char R_AMDGPU_REL64 = 5; +constexpr unsigned char R_386_GLOB_DAT = 6; +constexpr unsigned char R_X86_64_GLOB_DAT = 6; +constexpr unsigned char R_AMDGPU_ABS32 = 6; +constexpr unsigned char R_386_JMP_SLOT = 7; +constexpr unsigned char R_X86_64_JUMP_SLOT = 7; +constexpr unsigned char R_AMDGPU_GOTPCREL = 7; +constexpr unsigned char R_386_RELATIVE = 8; +constexpr unsigned char R_X86_64_RELATIVE = 8; +constexpr unsigned char R_AMDGPU_GOTPCREL32_LO = 8; +constexpr unsigned char R_386_GOTOFF = 9; +constexpr unsigned char R_X86_64_GOTPCREL = 9; +constexpr unsigned char R_AMDGPU_GOTPCREL32_HI = 9; +constexpr unsigned char R_386_GOTPC = 10; +constexpr unsigned char R_X86_64_32 = 10; +constexpr unsigned char R_AMDGPU_REL32_LO = 10; +constexpr unsigned char R_386_32PLT = 11; +constexpr unsigned char R_X86_64_32S = 11; +constexpr unsigned char R_AMDGPU_REL32_HI = 11; +constexpr unsigned char R_X86_64_16 = 12; +constexpr unsigned char R_X86_64_PC16 = 13; +constexpr unsigned char R_AMDGPU_RELATIVE64 = 13; +constexpr unsigned char R_386_TLS_TPOFF = 14; +constexpr unsigned char R_X86_64_8 = 14; +constexpr unsigned char R_386_TLS_IE = 15; +constexpr unsigned char R_X86_64_PC8 = 15; +constexpr unsigned char R_386_TLS_GOTIE = 16; +constexpr unsigned char R_X86_64_DTPMOD64 = 16; +constexpr unsigned char R_386_TLS_LE = 17; +constexpr unsigned char R_X86_64_DTPOFF64 = 17; +constexpr unsigned char R_386_TLS_GD = 18; +constexpr unsigned char R_X86_64_TPOFF64 = 18; +constexpr unsigned char R_386_TLS_LDM = 19; +constexpr unsigned char R_X86_64_TLSGD = 19; +constexpr unsigned char R_386_16 = 20; +constexpr unsigned char R_X86_64_TLSLD = 20; +constexpr unsigned char R_386_PC16 = 21; +constexpr unsigned char R_X86_64_DTPOFF32 = 21; +constexpr unsigned char R_386_8 = 22; +constexpr unsigned char R_X86_64_GOTTPOFF = 22; +constexpr unsigned char R_386_PC8 = 23; +constexpr unsigned char R_X86_64_TPOFF32 = 23; +constexpr unsigned char R_386_TLS_GD_32 = 24; +constexpr unsigned char R_X86_64_PC64 = 24; +constexpr unsigned char R_386_TLS_GD_PUSH = 25; +constexpr unsigned char R_X86_64_GOTOFF64 = 25; +constexpr unsigned char R_386_TLS_GD_CALL = 26; +constexpr unsigned char R_X86_64_GOTPC32 = 26; +constexpr unsigned char R_386_TLS_GD_POP = 27; +constexpr unsigned char R_X86_64_GOT64 = 27; +constexpr unsigned char R_386_TLS_LDM_32 = 28; +constexpr unsigned char R_X86_64_GOTPCREL64 = 28; +constexpr unsigned char R_386_TLS_LDM_PUSH = 29; +constexpr unsigned char R_X86_64_GOTPC64 = 29; +constexpr unsigned char R_386_TLS_LDM_CALL = 30; +constexpr unsigned char R_X86_64_GOTPLT64 = 30; +constexpr unsigned char R_386_TLS_LDM_POP = 31; +constexpr unsigned char R_X86_64_PLTOFF64 = 31; +constexpr unsigned char R_386_TLS_LDO_32 = 32; +constexpr unsigned char R_386_TLS_IE_32 = 33; +constexpr unsigned char R_386_TLS_LE_32 = 34; +constexpr unsigned char R_X86_64_GOTPC32_TLSDESC = 34; +constexpr unsigned char R_386_TLS_DTPMOD32 = 35; +constexpr unsigned char R_X86_64_TLSDESC_CALL = 35; +constexpr unsigned char R_386_TLS_DTPOFF32 = 36; +constexpr unsigned char R_X86_64_TLSDESC = 36; +constexpr unsigned char R_386_TLS_TPOFF32 = 37; +constexpr unsigned char R_X86_64_IRELATIVE = 37; +constexpr unsigned char R_386_SIZE32 = 38; +constexpr unsigned char R_386_TLS_GOTDESC = 39; +constexpr unsigned char R_386_TLS_DESC_CALL = 40; +constexpr unsigned char R_386_TLS_DESC = 41; +constexpr unsigned char R_386_IRELATIVE = 42; +constexpr unsigned char R_386_GOT32X = 43; +constexpr unsigned char R_X86_64_GNU_VTINHERIT = 250; +constexpr unsigned char R_X86_64_GNU_VTENTRY = 251; + +// Segment types +constexpr Elf_Word PT_NULL = 0; +constexpr Elf_Word PT_LOAD = 1; +constexpr Elf_Word PT_DYNAMIC = 2; +constexpr Elf_Word PT_INTERP = 3; +constexpr Elf_Word PT_NOTE = 4; +constexpr Elf_Word PT_SHLIB = 5; +constexpr Elf_Word PT_PHDR = 6; +constexpr Elf_Word PT_TLS = 7; +constexpr Elf_Word PT_LOOS = 0X60000000; +constexpr Elf_Word PT_GNU_EH_FRAME = 0X6474E550; // Frame unwind information +constexpr Elf_Word PT_GNU_STACK = 0X6474E551; // Stack flags +constexpr Elf_Word PT_GNU_RELRO = 0X6474E552; // Read only after relocs +constexpr Elf_Word PT_GNU_PROPERTY = 0X6474E553; // GNU property +constexpr Elf_Word PT_GNU_MBIND_LO = 0X6474E555; // Mbind segments start +constexpr Elf_Word PT_GNU_MBIND_HI = 0X6474F554; // Mbind segments finish +constexpr Elf_Word PT_PAX_FLAGS = 0X65041580; +constexpr Elf_Word PT_OPENBSD_RANDOMIZE = 0X65A3DBE6; +constexpr Elf_Word PT_OPENBSD_WXNEEDED = 0X65A3DBE7; +constexpr Elf_Word PT_OPENBSD_BOOTDATA = 0X65A41BE6; +constexpr Elf_Word PT_SUNWSTACK = 0X6FFFFFFB; +constexpr Elf_Word PT_HIOS = 0X6FFFFFFF; +constexpr Elf_Word PT_LOPROC = 0X70000000; +constexpr Elf_Word PT_HIPROC = 0X7FFFFFFF; + +// Segment flags +constexpr Elf_Word PF_X = 1; // Execute +constexpr Elf_Word PF_W = 2; // Write +constexpr Elf_Word PF_R = 4; // Read +constexpr Elf_Word PF_MASKOS = 0x0ff00000; // Unspecified +constexpr Elf_Word PF_MASKPROC = 0xf0000000; // Unspecified + +// Dynamic Array Tags +constexpr Elf_Word DT_NULL = 0; +constexpr Elf_Word DT_NEEDED = 1; +constexpr Elf_Word DT_PLTRELSZ = 2; +constexpr Elf_Word DT_PLTGOT = 3; +constexpr Elf_Word DT_HASH = 4; +constexpr Elf_Word DT_STRTAB = 5; +constexpr Elf_Word DT_SYMTAB = 6; +constexpr Elf_Word DT_RELA = 7; +constexpr Elf_Word DT_RELASZ = 8; +constexpr Elf_Word DT_RELAENT = 9; +constexpr Elf_Word DT_STRSZ = 10; +constexpr Elf_Word DT_SYMENT = 11; +constexpr Elf_Word DT_INIT = 12; +constexpr Elf_Word DT_FINI = 13; +constexpr Elf_Word DT_SONAME = 14; +constexpr Elf_Word DT_RPATH = 15; +constexpr Elf_Word DT_SYMBOLIC = 16; +constexpr Elf_Word DT_REL = 17; +constexpr Elf_Word DT_RELSZ = 18; +constexpr Elf_Word DT_RELENT = 19; +constexpr Elf_Word DT_PLTREL = 20; +constexpr Elf_Word DT_DEBUG = 21; +constexpr Elf_Word DT_TEXTREL = 22; +constexpr Elf_Word DT_JMPREL = 23; +constexpr Elf_Word DT_BIND_NOW = 24; +constexpr Elf_Word DT_INIT_ARRAY = 25; +constexpr Elf_Word DT_FINI_ARRAY = 26; +constexpr Elf_Word DT_INIT_ARRAYSZ = 27; +constexpr Elf_Word DT_FINI_ARRAYSZ = 28; +constexpr Elf_Word DT_RUNPATH = 29; +constexpr Elf_Word DT_FLAGS = 30; +constexpr Elf_Word DT_ENCODING = 32; +constexpr Elf_Word DT_PREINIT_ARRAY = 32; +constexpr Elf_Word DT_PREINIT_ARRAYSZ = 33; +constexpr Elf_Word DT_MAXPOSTAGS = 34; +constexpr Elf_Word DT_GNU_HASH = 0x6ffffef5; +constexpr Elf_Word DT_VERSYM = 0x6ffffff0; +constexpr Elf_Word DT_FLAGS_1 = 0x6ffffffb; +constexpr Elf_Word DT_VERNEED = 0x6ffffffe; +constexpr Elf_Word DT_VERNEEDNUM = 0x6fffffff; +constexpr Elf_Word DT_LOOS = 0x6000000D; +constexpr Elf_Word DT_HIOS = 0x6ffff000; +constexpr Elf_Word DT_LOPROC = 0x70000000; +constexpr Elf_Word DT_HIPROC = 0x7FFFFFFF; + +// DT_FLAGS values +constexpr Elf_Word DF_ORIGIN = 0x1; +constexpr Elf_Word DF_SYMBOLIC = 0x2; +constexpr Elf_Word DF_TEXTREL = 0x4; +constexpr Elf_Word DF_BIND_NOW = 0x8; +constexpr Elf_Word DF_STATIC_TLS = 0x10; + +// ELF file header +struct Elf32_Ehdr +{ + unsigned char e_ident[EI_NIDENT]; + Elf_Half e_type; + Elf_Half e_machine; + Elf_Word e_version; + Elf32_Addr e_entry; + Elf32_Off e_phoff; + Elf32_Off e_shoff; + Elf_Word e_flags; + Elf_Half e_ehsize; + Elf_Half e_phentsize; + Elf_Half e_phnum; + Elf_Half e_shentsize; + Elf_Half e_shnum; + Elf_Half e_shstrndx; +}; + +struct Elf64_Ehdr +{ + unsigned char e_ident[EI_NIDENT]; + Elf_Half e_type; + Elf_Half e_machine; + Elf_Word e_version; + Elf64_Addr e_entry; + Elf64_Off e_phoff; + Elf64_Off e_shoff; + Elf_Word e_flags; + Elf_Half e_ehsize; + Elf_Half e_phentsize; + Elf_Half e_phnum; + Elf_Half e_shentsize; + Elf_Half e_shnum; + Elf_Half e_shstrndx; +}; + +// Section header +struct Elf32_Shdr +{ + Elf_Word sh_name; + Elf_Word sh_type; + Elf_Word sh_flags; + Elf32_Addr sh_addr; + Elf32_Off sh_offset; + Elf_Word sh_size; + Elf_Word sh_link; + Elf_Word sh_info; + Elf_Word sh_addralign; + Elf_Word sh_entsize; +}; + +struct Elf64_Shdr +{ + Elf_Word sh_name; + Elf_Word sh_type; + Elf_Xword sh_flags; + Elf64_Addr sh_addr; + Elf64_Off sh_offset; + Elf_Xword sh_size; + Elf_Word sh_link; + Elf_Word sh_info; + Elf_Xword sh_addralign; + Elf_Xword sh_entsize; +}; + +// Segment header +struct Elf32_Phdr +{ + Elf_Word p_type; + Elf32_Off p_offset; + Elf32_Addr p_vaddr; + Elf32_Addr p_paddr; + Elf_Word p_filesz; + Elf_Word p_memsz; + Elf_Word p_flags; + Elf_Word p_align; +}; + +struct Elf64_Phdr +{ + Elf_Word p_type; + Elf_Word p_flags; + Elf64_Off p_offset; + Elf64_Addr p_vaddr; + Elf64_Addr p_paddr; + Elf_Xword p_filesz; + Elf_Xword p_memsz; + Elf_Xword p_align; +}; + +// Symbol table entry +struct Elf32_Sym +{ + Elf_Word st_name; + Elf32_Addr st_value; + Elf_Word st_size; + unsigned char st_info; + unsigned char st_other; + Elf_Half st_shndx; +}; + +struct Elf64_Sym +{ + Elf_Word st_name; + unsigned char st_info; + unsigned char st_other; + Elf_Half st_shndx; + Elf64_Addr st_value; + Elf_Xword st_size; +}; + +#define ELF_ST_BIND( i ) ( ( i ) >> 4 ) +#define ELF_ST_TYPE( i ) ( (i)&0xf ) +#define ELF_ST_INFO( b, t ) ( ( ( b ) << 4 ) + ( (t)&0xf ) ) + +#define ELF_ST_VISIBILITY( o ) ( (o)&0x3 ) + +// Relocation entries +struct Elf32_Rel +{ + Elf32_Addr r_offset; + Elf_Word r_info; +}; + +struct Elf32_Rela +{ + Elf32_Addr r_offset; + Elf_Word r_info; + Elf_Sword r_addend; +}; + +struct Elf64_Rel +{ + Elf64_Addr r_offset; + Elf_Xword r_info; +}; + +struct Elf64_Rela +{ + Elf64_Addr r_offset; + Elf_Xword r_info; + Elf_Sxword r_addend; +}; + +#define ELF32_R_SYM( i ) ( ( i ) >> 8 ) +#define ELF32_R_TYPE( i ) ( (unsigned char)( i ) ) +#define ELF32_R_INFO( s, t ) ( ( ( s ) << 8 ) + (unsigned char)( t ) ) + +#define ELF64_R_SYM( i ) ( ( i ) >> 32 ) +#define ELF64_R_TYPE( i ) ( (i)&0xffffffffL ) +#define ELF64_R_INFO( s, t ) \ + ( ( ( (int64_t)( s ) ) << 32 ) + ( (t)&0xffffffffL ) ) + +// Dynamic structure +struct Elf32_Dyn +{ + Elf_Sword d_tag; + union { + Elf_Word d_val; + Elf32_Addr d_ptr; + } d_un; +}; + +struct Elf64_Dyn +{ + Elf_Sxword d_tag; + union { + Elf_Xword d_val; + Elf64_Addr d_ptr; + } d_un; +}; + +struct Elfxx_Verneed +{ + Elf_Half vn_version; + Elf_Half vn_cnt; + Elf_Word vn_file; + Elf_Word vn_aux; + Elf_Word vn_next; +}; + +struct Elfxx_Vernaux +{ + Elf_Word vna_hash; + Elf_Half vna_flags; + Elf_Half vna_other; + Elf_Word vna_name; + Elf_Word vna_next; +}; + +#ifdef __cplusplus +} // namespace ELFIO +#endif + +#endif // ELFTYPES_H diff --git a/tools/elfio/elfio.hpp b/tools/elfio/elfio.hpp new file mode 100644 index 00000000000..25097a17fa9 --- /dev/null +++ b/tools/elfio/elfio.hpp @@ -0,0 +1,1048 @@ +/* +Copyright (C) 2001-present by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELFIO_HPP +#define ELFIO_HPP + +#include +#include +#include +#include +#include +#include +#include + +#include "elf_types.hpp" +#include "elfio_version.hpp" +#include "elfio_utils.hpp" +#include "elfio_header.hpp" +#include "elfio_section.hpp" +#include "elfio_segment.hpp" +#include "elfio_strings.hpp" + +#define ELFIO_HEADER_ACCESS_GET( TYPE, FNAME ) \ + TYPE get_##FNAME() const { return header ? ( header->get_##FNAME() ) : 0; } + +#define ELFIO_HEADER_ACCESS_GET_SET( TYPE, FNAME ) \ + TYPE get_##FNAME() const \ + { \ + return header ? ( header->get_##FNAME() ) : 0; \ + } \ + void set_##FNAME( TYPE val ) \ + { \ + if ( header ) { \ + header->set_##FNAME( val ); \ + } \ + } + +namespace ELFIO { + +//------------------------------------------------------------------------------ +class elfio +{ + public: + //------------------------------------------------------------------------------ + elfio() noexcept : sections( this ), segments( this ) + { + header = nullptr; + current_file_pos = 0; + create( ELFCLASS32, ELFDATA2LSB ); + } + + elfio( elfio&& other ) noexcept : sections( this ), segments( this ) + { + header = std::move( other.header ); + sections_ = std::move( other.sections_ ); + segments_ = std::move( other.segments_ ); + convertor = std::move( other.convertor ); + addr_translator = std::move( other.addr_translator ); + current_file_pos = std::move( other.current_file_pos ); + + other.header = nullptr; + other.sections_.clear(); + other.segments_.clear(); + } + + elfio& operator=( elfio&& other ) noexcept + { + if ( this != &other ) { + clean(); + + header = std::move( other.header ); + sections_ = std::move( other.sections_ ); + segments_ = std::move( other.segments_ ); + convertor = std::move( other.convertor ); + addr_translator = std::move( other.addr_translator ); + current_file_pos = std::move( other.current_file_pos ); + + other.header = nullptr; + other.sections_.clear(); + other.segments_.clear(); + } + return *this; + } + + //------------------------------------------------------------------------------ + // clang-format off + elfio( const elfio& ) = delete; + elfio& operator=( const elfio& ) = delete; + // clang-format on + + //------------------------------------------------------------------------------ + ~elfio() { clean(); } + + //------------------------------------------------------------------------------ + void create( unsigned char file_class, unsigned char encoding ) + { + clean(); + convertor.setup( encoding ); + header = create_header( file_class, encoding ); + create_mandatory_sections(); + } + + void set_address_translation( std::vector& addr_trans ) + { + addr_translator.set_address_translation( addr_trans ); + } + + //------------------------------------------------------------------------------ + bool load( const std::string& file_name ) + { + std::ifstream stream; + stream.open( file_name.c_str(), std::ios::in | std::ios::binary ); + if ( !stream ) { + return false; + } + + return load( stream ); + } + + //------------------------------------------------------------------------------ + bool load( std::istream& stream ) + { + clean(); + + unsigned char e_ident[EI_NIDENT] = { 0 }; + // Read ELF file signature + stream.seekg( addr_translator[0] ); + stream.read( reinterpret_cast( &e_ident ), sizeof( e_ident ) ); + + // Is it ELF file? + if ( stream.gcount() != sizeof( e_ident ) || + e_ident[EI_MAG0] != ELFMAG0 || e_ident[EI_MAG1] != ELFMAG1 || + e_ident[EI_MAG2] != ELFMAG2 || e_ident[EI_MAG3] != ELFMAG3 ) { + return false; + } + + if ( ( e_ident[EI_CLASS] != ELFCLASS64 ) && + ( e_ident[EI_CLASS] != ELFCLASS32 ) ) { + return false; + } + + if ( ( e_ident[EI_DATA] != ELFDATA2LSB ) && + ( e_ident[EI_DATA] != ELFDATA2MSB ) ) { + return false; + } + + convertor.setup( e_ident[EI_DATA] ); + header = create_header( e_ident[EI_CLASS], e_ident[EI_DATA] ); + if ( nullptr == header ) { + return false; + } + if ( !header->load( stream ) ) { + return false; + } + + load_sections( stream ); + bool is_still_good = load_segments( stream ); + return is_still_good; + } + + //------------------------------------------------------------------------------ + bool save( const std::string& file_name ) + { + std::ofstream stream; + stream.open( file_name.c_str(), std::ios::out | std::ios::binary ); + if ( !stream ) { + return false; + } + + return save( stream ); + } + + //------------------------------------------------------------------------------ + bool save( std::ostream& stream ) + { + if ( !stream || header == nullptr ) { + return false; + } + + // Define layout specific header fields + // The position of the segment table is fixed after the header. + // The position of the section table is variable and needs to be fixed + // before saving. + header->set_segments_num( segments.size() ); + header->set_segments_offset( + segments.size() > 0 ? header->get_header_size() : 0 ); + header->set_sections_num( sections.size() ); + header->set_sections_offset( 0 ); + + // Layout the first section right after the segment table + current_file_pos = + header->get_header_size() + + header->get_segment_entry_size() * + static_cast( header->get_segments_num() ); + + calc_segment_alignment(); + + bool is_still_good = layout_segments_and_their_sections(); + is_still_good = is_still_good && layout_sections_without_segments(); + is_still_good = is_still_good && layout_section_table(); + + is_still_good = is_still_good && save_header( stream ); + is_still_good = is_still_good && save_sections( stream ); + is_still_good = is_still_good && save_segments( stream ); + + return is_still_good; + } + + //------------------------------------------------------------------------------ + // ELF header access functions + ELFIO_HEADER_ACCESS_GET( unsigned char, class ); + ELFIO_HEADER_ACCESS_GET( unsigned char, elf_version ); + ELFIO_HEADER_ACCESS_GET( unsigned char, encoding ); + ELFIO_HEADER_ACCESS_GET( Elf_Word, version ); + ELFIO_HEADER_ACCESS_GET( Elf_Half, header_size ); + ELFIO_HEADER_ACCESS_GET( Elf_Half, section_entry_size ); + ELFIO_HEADER_ACCESS_GET( Elf_Half, segment_entry_size ); + + ELFIO_HEADER_ACCESS_GET_SET( unsigned char, os_abi ); + ELFIO_HEADER_ACCESS_GET_SET( unsigned char, abi_version ); + ELFIO_HEADER_ACCESS_GET_SET( Elf_Half, type ); + ELFIO_HEADER_ACCESS_GET_SET( Elf_Half, machine ); + ELFIO_HEADER_ACCESS_GET_SET( Elf_Word, flags ); + ELFIO_HEADER_ACCESS_GET_SET( Elf64_Addr, entry ); + ELFIO_HEADER_ACCESS_GET_SET( Elf64_Off, sections_offset ); + ELFIO_HEADER_ACCESS_GET_SET( Elf64_Off, segments_offset ); + ELFIO_HEADER_ACCESS_GET_SET( Elf_Half, section_name_str_index ); + + //------------------------------------------------------------------------------ + const endianess_convertor& get_convertor() const { return convertor; } + + //------------------------------------------------------------------------------ + Elf_Xword get_default_entry_size( Elf_Word section_type ) const + { + switch ( section_type ) { + case SHT_RELA: + if ( header->get_class() == ELFCLASS64 ) { + return sizeof( Elf64_Rela ); + } + else { + return sizeof( Elf32_Rela ); + } + case SHT_REL: + if ( header->get_class() == ELFCLASS64 ) { + return sizeof( Elf64_Rel ); + } + else { + return sizeof( Elf32_Rel ); + } + case SHT_SYMTAB: + if ( header->get_class() == ELFCLASS64 ) { + return sizeof( Elf64_Sym ); + } + else { + return sizeof( Elf32_Sym ); + } + case SHT_DYNAMIC: + if ( header->get_class() == ELFCLASS64 ) { + return sizeof( Elf64_Dyn ); + } + else { + return sizeof( Elf32_Dyn ); + } + default: + return 0; + } + } + + //------------------------------------------------------------------------------ + //! returns an empty string if no problems are detected, + //! or a string containing an error message if problems are found, + //! with one error per line. + std::string validate() const + { + // clang-format off + + std::string errors; + // Check for overlapping sections in the file + // This is explicitly forbidden by ELF specification + for ( int i = 0; i < sections.size(); ++i) { + for ( int j = i+1; j < sections.size(); ++j ) { + const section* a = sections[i]; + const section* b = sections[j]; + if ( ((a->get_type() & SHT_NOBITS) == 0) + && ((b->get_type() & SHT_NOBITS) == 0) + && (a->get_size() > 0) + && (b->get_size() > 0) + && (a->get_offset() > 0) + && (b->get_offset() > 0)) { + if ( is_offset_in_section( a->get_offset(), b ) + || is_offset_in_section( a->get_offset()+a->get_size()-1, b ) + || is_offset_in_section( b->get_offset(), a ) + || is_offset_in_section( b->get_offset()+b->get_size()-1, a )) { + errors += "Sections " + a->get_name() + " and " + b->get_name() + " overlap in file\n"; + } + } + } + } + + // Check for conflicting section / program header tables, where + // the same offset has different vaddresses in section table and + // program header table. + // This doesn't seem to be explicitly forbidden by ELF specification, + // but: + // - it doesn't make any sense + // - ELFIO relies on this being consistent when writing ELF files, + // since offsets are re-calculated from vaddress + for ( int h = 0; h < segments.size(); ++h ) { + const segment* seg = segments[h]; + if ( seg->get_type() == PT_LOAD && seg->get_file_size() > 0 ) { + const section* sec = find_prog_section_for_offset( seg->get_offset() ); + if ( sec != nullptr ) { + Elf64_Addr sec_addr = get_virtual_addr( seg->get_offset(), sec ); + if ( sec_addr != seg->get_virtual_address() ) { + errors += "Virtual address of segment " + std::to_string( h ) + " (" + to_hex_string( seg->get_virtual_address() ) + ")" + + " conflicts with address of section " + sec->get_name() + " (" + to_hex_string( sec_addr ) + ")" + + " at offset " + to_hex_string( seg->get_offset() ) + "\n"; + } + } + } + } + + // more checks to be added here... + + return errors; + // clang-format on + } + + private: + //------------------------------------------------------------------------------ + static bool is_offset_in_section( Elf64_Off offset, const section* sec ) + { + return ( offset >= sec->get_offset() ) && + ( offset < ( sec->get_offset() + sec->get_size() ) ); + } + + //------------------------------------------------------------------------------ + static Elf64_Addr get_virtual_addr( Elf64_Off offset, const section* sec ) + { + return sec->get_address() + offset - sec->get_offset(); + } + + //------------------------------------------------------------------------------ + const section* find_prog_section_for_offset( Elf64_Off offset ) const + { + for ( auto* sec : sections ) { + if ( sec->get_type() == SHT_PROGBITS && + is_offset_in_section( offset, sec ) ) { + return sec; + } + } + return nullptr; + } + + //------------------------------------------------------------------------------ + void clean() + { + delete header; + header = nullptr; + + for ( auto* it : sections_ ) { + delete it; + } + sections_.clear(); + + for ( auto* it : segments_ ) { + delete it; + } + segments_.clear(); + } + + //------------------------------------------------------------------------------ + elf_header* create_header( unsigned char file_class, + unsigned char encoding ) + { + elf_header* new_header = nullptr; + + if ( file_class == ELFCLASS64 ) { + new_header = new elf_header_impl( &convertor, encoding, + &addr_translator ); + } + else if ( file_class == ELFCLASS32 ) { + new_header = new elf_header_impl( &convertor, encoding, + &addr_translator ); + } + else { + return nullptr; + } + + return new_header; + } + + //------------------------------------------------------------------------------ + section* create_section() + { + section* new_section = nullptr; + unsigned char file_class = get_class(); + + if ( file_class == ELFCLASS64 ) { + new_section = + new section_impl( &convertor, &addr_translator ); + } + else if ( file_class == ELFCLASS32 ) { + new_section = + new section_impl( &convertor, &addr_translator ); + } + else { + return nullptr; + } + + new_section->set_index( static_cast( sections_.size() ) ); + sections_.emplace_back( new_section ); + + return new_section; + } + + //------------------------------------------------------------------------------ + segment* create_segment() + { + segment* new_segment = nullptr; + unsigned char file_class = header->get_class(); + + if ( file_class == ELFCLASS64 ) { + new_segment = + new segment_impl( &convertor, &addr_translator ); + } + else if ( file_class == ELFCLASS32 ) { + new_segment = + new segment_impl( &convertor, &addr_translator ); + } + else { + return nullptr; + } + + new_segment->set_index( static_cast( segments_.size() ) ); + segments_.emplace_back( new_segment ); + + return new_segment; + } + + //------------------------------------------------------------------------------ + void create_mandatory_sections() + { + // Create null section without calling to 'add_section' as no string + // section containing section names exists yet + section* sec0 = create_section(); + sec0->set_index( 0 ); + sec0->set_name( "" ); + sec0->set_name_string_offset( 0 ); + + set_section_name_str_index( 1 ); + section* shstrtab = sections.add( ".shstrtab" ); + shstrtab->set_type( SHT_STRTAB ); + shstrtab->set_addr_align( 1 ); + } + + //------------------------------------------------------------------------------ + Elf_Half load_sections( std::istream& stream ) + { + Elf_Half entry_size = header->get_section_entry_size(); + Elf_Half num = header->get_sections_num(); + Elf64_Off offset = header->get_sections_offset(); + + for ( Elf_Half i = 0; i < num; ++i ) { + section* sec = create_section(); + sec->load( stream, + static_cast( offset ) + + static_cast( i ) * entry_size ); + sec->set_index( i ); + // To mark that the section is not permitted to reassign address + // during layout calculation + sec->set_address( sec->get_address() ); + } + + Elf_Half shstrndx = get_section_name_str_index(); + + if ( SHN_UNDEF != shstrndx ) { + string_section_accessor str_reader( sections[shstrndx] ); + for ( Elf_Half i = 0; i < num; ++i ) { + Elf_Word section_offset = sections[i]->get_name_string_offset(); + const char* p = str_reader.get_string( section_offset ); + if ( p != nullptr ) { + sections[i]->set_name( p ); + } + } + } + + return num; + } + + //------------------------------------------------------------------------------ + //! Checks whether the addresses of the section entirely fall within the given segment. + //! It doesn't matter if the addresses are memory addresses, or file offsets, + //! they just need to be in the same address space + static bool is_sect_in_seg( Elf64_Off sect_begin, + Elf_Xword sect_size, + Elf64_Off seg_begin, + Elf64_Off seg_end ) + { + return ( seg_begin <= sect_begin ) && + ( sect_begin + sect_size <= seg_end ) && + ( sect_begin < + seg_end ); // this is important criteria when sect_size == 0 + // Example: seg_begin=10, seg_end=12 (-> covering the bytes 10 and 11) + // sect_begin=12, sect_size=0 -> shall return false! + } + + //------------------------------------------------------------------------------ + bool load_segments( std::istream& stream ) + { + Elf_Half entry_size = header->get_segment_entry_size(); + Elf_Half num = header->get_segments_num(); + Elf64_Off offset = header->get_segments_offset(); + + for ( Elf_Half i = 0; i < num; ++i ) { + segment* seg = nullptr; + unsigned char file_class = header->get_class(); + + if ( file_class == ELFCLASS64 ) { + seg = new segment_impl( &convertor, + &addr_translator ); + } + else if ( file_class == ELFCLASS32 ) { + seg = new segment_impl( &convertor, + &addr_translator ); + } + else { + return false; + } + + seg->load( stream, + static_cast( offset ) + + static_cast( i ) * entry_size ); + seg->set_index( i ); + + // Add sections to the segments (similar to readelfs algorithm) + Elf64_Off segBaseOffset = seg->get_offset(); + Elf64_Off segEndOffset = segBaseOffset + seg->get_file_size(); + Elf64_Off segVBaseAddr = seg->get_virtual_address(); + Elf64_Off segVEndAddr = segVBaseAddr + seg->get_memory_size(); + for ( auto* psec : sections ) { + // SHF_ALLOC sections are matched based on the virtual address + // otherwise the file offset is matched + if ( ( ( psec->get_flags() & SHF_ALLOC ) == SHF_ALLOC ) + ? is_sect_in_seg( psec->get_address(), + psec->get_size(), segVBaseAddr, + segVEndAddr ) + : is_sect_in_seg( psec->get_offset(), psec->get_size(), + segBaseOffset, segEndOffset ) ) { + // Alignment of segment shall not be updated, to preserve original value + // It will be re-calculated on saving. + seg->add_section_index( psec->get_index(), 0 ); + } + } + + // Add section into the segments' container + segments_.emplace_back( seg ); + } + + return true; + } + + //------------------------------------------------------------------------------ + bool save_header( std::ostream& stream ) { return header->save( stream ); } + + //------------------------------------------------------------------------------ + bool save_sections( std::ostream& stream ) + { + for ( auto* sec : sections_ ) { + std::streampos headerPosition = + static_cast( header->get_sections_offset() ) + + static_cast( + header->get_section_entry_size() ) * + sec->get_index(); + + sec->save( stream, headerPosition, sec->get_offset() ); + } + return true; + } + + //------------------------------------------------------------------------------ + bool save_segments( std::ostream& stream ) + { + for ( auto* seg : segments_ ) { + std::streampos headerPosition = + static_cast( header->get_segments_offset() ) + + static_cast( + header->get_segment_entry_size() ) * + seg->get_index(); + + seg->save( stream, headerPosition, seg->get_offset() ); + } + return true; + } + + //------------------------------------------------------------------------------ + bool is_section_without_segment( unsigned int section_index ) const + { + bool found = false; + + for ( unsigned int j = 0; !found && ( j < segments.size() ); ++j ) { + for ( unsigned int k = 0; + !found && ( k < segments[j]->get_sections_num() ); ++k ) { + found = segments[j]->get_section_index_at( k ) == section_index; + } + } + + return !found; + } + + //------------------------------------------------------------------------------ + static bool is_subsequence_of( segment* seg1, segment* seg2 ) + { + // Return 'true' if sections of seg1 are a subset of sections in seg2 + const std::vector& sections1 = seg1->get_sections(); + const std::vector& sections2 = seg2->get_sections(); + + bool found = false; + if ( sections1.size() < sections2.size() ) { + found = std::includes( sections2.begin(), sections2.end(), + sections1.begin(), sections1.end() ); + } + + return found; + } + + //------------------------------------------------------------------------------ + std::vector get_ordered_segments() + { + std::vector res; + std::deque worklist; + + res.reserve( segments.size() ); + std::copy( segments_.begin(), segments_.end(), + std::back_inserter( worklist ) ); + + // Bring the segments which start at address 0 to the front + size_t nextSlot = 0; + for ( size_t i = 0; i < worklist.size(); ++i ) { + if ( i != nextSlot && worklist[i]->is_offset_initialized() && + worklist[i]->get_offset() == 0 ) { + if ( worklist[nextSlot]->get_offset() == 0 ) { + ++nextSlot; + } + std::swap( worklist[i], worklist[nextSlot] ); + ++nextSlot; + } + } + + while ( !worklist.empty() ) { + segment* seg = worklist.front(); + worklist.pop_front(); + + size_t i = 0; + for ( ; i < worklist.size(); ++i ) { + if ( is_subsequence_of( seg, worklist[i] ) ) { + break; + } + } + + if ( i < worklist.size() ) { + worklist.emplace_back( seg ); + } + else { + res.emplace_back( seg ); + } + } + + return res; + } + + //------------------------------------------------------------------------------ + bool layout_sections_without_segments() + { + for ( unsigned int i = 0; i < sections_.size(); ++i ) { + if ( is_section_without_segment( i ) ) { + section* sec = sections_[i]; + + Elf_Xword section_align = sec->get_addr_align(); + if ( section_align > 1 && + current_file_pos % section_align != 0 ) { + current_file_pos += + section_align - current_file_pos % section_align; + } + + if ( 0 != sec->get_index() ) { + sec->set_offset( current_file_pos ); + } + + if ( SHT_NOBITS != sec->get_type() && + SHT_NULL != sec->get_type() ) { + current_file_pos += sec->get_size(); + } + } + } + + return true; + } + + //------------------------------------------------------------------------------ + void calc_segment_alignment() + { + for ( auto* seg : segments_ ) { + for ( int i = 0; i < seg->get_sections_num(); ++i ) { + section* sect = sections_[seg->get_section_index_at( i )]; + if ( sect->get_addr_align() > seg->get_align() ) { + seg->set_align( sect->get_addr_align() ); + } + } + } + } + + //------------------------------------------------------------------------------ + bool layout_segments_and_their_sections() + { + std::vector worklist; + std::vector section_generated( sections.size(), false ); + + // Get segments in a order in where segments which contain a + // sub sequence of other segments are located at the end + worklist = get_ordered_segments(); + + for ( auto* seg : worklist ) { + Elf_Xword segment_memory = 0; + Elf_Xword segment_filesize = 0; + Elf_Xword seg_start_pos = current_file_pos; + // Special case: PHDR segment + // This segment contains the program headers but no sections + if ( seg->get_type() == PT_PHDR && seg->get_sections_num() == 0 ) { + seg_start_pos = header->get_segments_offset(); + segment_memory = segment_filesize = + header->get_segment_entry_size() * + static_cast( header->get_segments_num() ); + } + // Special case: + else if ( seg->is_offset_initialized() && seg->get_offset() == 0 ) { + seg_start_pos = 0; + if ( seg->get_sections_num() > 0 ) { + segment_memory = segment_filesize = current_file_pos; + } + } + // New segments with not generated sections + // have to be aligned + else if ( seg->get_sections_num() > 0 && + !section_generated[seg->get_section_index_at( 0 )] ) { + Elf_Xword align = seg->get_align() > 0 ? seg->get_align() : 1; + Elf64_Off cur_page_alignment = current_file_pos % align; + Elf64_Off req_page_alignment = + seg->get_virtual_address() % align; + Elf64_Off error = req_page_alignment - cur_page_alignment; + + current_file_pos += ( seg->get_align() + error ) % align; + seg_start_pos = current_file_pos; + } + else if ( seg->get_sections_num() > 0 ) { + seg_start_pos = + sections[seg->get_section_index_at( 0 )]->get_offset(); + } + + // Write segment's data + for ( auto j = 0; j < seg->get_sections_num(); ++j ) { + Elf_Half index = seg->get_section_index_at( j ); + + section* sec = sections[index]; + + // The NULL section is always generated + if ( SHT_NULL == sec->get_type() ) { + section_generated[index] = true; + continue; + } + + Elf_Xword section_align = 0; + // Fix up the alignment + if ( !section_generated[index] && + sec->is_address_initialized() && + SHT_NOBITS != sec->get_type() && + SHT_NULL != sec->get_type() && 0 != sec->get_size() ) { + // Align the sections based on the virtual addresses + // when possible (this is what matters for execution) + Elf64_Off req_offset = + sec->get_address() - seg->get_virtual_address(); + Elf64_Off cur_offset = current_file_pos - seg_start_pos; + if ( req_offset < cur_offset ) { + // something has gone awfully wrong, abort! + // section_align would turn out negative, seeking backwards and overwriting previous data + return false; + } + section_align = req_offset - cur_offset; + } + else if ( !section_generated[index] && + !sec->is_address_initialized() ) { + // If no address has been specified then only the section + // alignment constraint has to be matched + Elf_Xword align = sec->get_addr_align(); + if ( align == 0 ) { + align = 1; + } + Elf64_Off error = current_file_pos % align; + section_align = ( align - error ) % align; + } + else if ( section_generated[index] ) { + // Alignment for already generated sections + section_align = + sec->get_offset() - seg_start_pos - segment_filesize; + } + + // Determine the segment file and memory sizes + // Special case .tbss section (NOBITS) in non TLS segment + if ( ( ( sec->get_flags() & SHF_ALLOC ) == SHF_ALLOC ) && + !( ( ( sec->get_flags() & SHF_TLS ) == SHF_TLS ) && + ( seg->get_type() != PT_TLS ) && + ( SHT_NOBITS == sec->get_type() ) ) ) { + segment_memory += sec->get_size() + section_align; + } + + if ( SHT_NOBITS != sec->get_type() ) { + segment_filesize += sec->get_size() + section_align; + } + + // Nothing to be done when generating nested segments + if ( section_generated[index] ) { + continue; + } + + current_file_pos += section_align; + + // Set the section addresses when missing + if ( !sec->is_address_initialized() ) { + sec->set_address( seg->get_virtual_address() + + current_file_pos - seg_start_pos ); + } + + if ( 0 != sec->get_index() ) { + sec->set_offset( current_file_pos ); + } + + if ( SHT_NOBITS != sec->get_type() ) { + current_file_pos += sec->get_size(); + } + + section_generated[index] = true; + } + + seg->set_file_size( segment_filesize ); + + // If we already have a memory size from loading an elf file (value > 0), + // it must not shrink! + // Memory size may be bigger than file size and it is the loader's job to do something + // with the surplus bytes in memory, like initializing them with a defined value. + if ( seg->get_memory_size() < segment_memory ) { + seg->set_memory_size( segment_memory ); + } + + seg->set_offset( seg_start_pos ); + } + + return true; + } + + //------------------------------------------------------------------------------ + bool layout_section_table() + { + // Simply place the section table at the end for now + Elf64_Off alignmentError = current_file_pos % 4; + current_file_pos += ( 4 - alignmentError ) % 4; + header->set_sections_offset( current_file_pos ); + return true; + } + + //------------------------------------------------------------------------------ + public: + friend class Sections; + class Sections + { + public: + //------------------------------------------------------------------------------ + explicit Sections( elfio* parent ) : parent( parent ) {} + + //------------------------------------------------------------------------------ + Elf_Half size() const + { + return static_cast( parent->sections_.size() ); + } + + //------------------------------------------------------------------------------ + section* operator[]( unsigned int index ) const + { + section* sec = nullptr; + + if ( index < parent->sections_.size() ) { + sec = parent->sections_[index]; + } + + return sec; + } + + //------------------------------------------------------------------------------ + section* operator[]( const std::string& name ) const + { + section* sec = nullptr; + + for ( auto* it : parent->sections_ ) { + if ( it->get_name() == name ) { + sec = it; + break; + } + } + + return sec; + } + + //------------------------------------------------------------------------------ + section* add( const std::string& name ) + { + section* new_section = parent->create_section(); + new_section->set_name( name ); + + Elf_Half str_index = parent->get_section_name_str_index(); + section* string_table( parent->sections_[str_index] ); + string_section_accessor str_writer( string_table ); + Elf_Word pos = str_writer.add_string( name ); + new_section->set_name_string_offset( pos ); + + return new_section; + } + + //------------------------------------------------------------------------------ + std::vector::iterator begin() + { + return parent->sections_.begin(); + } + + //------------------------------------------------------------------------------ + std::vector::iterator end() + { + return parent->sections_.end(); + } + + //------------------------------------------------------------------------------ + std::vector::const_iterator begin() const + { + return parent->sections_.cbegin(); + } + + //------------------------------------------------------------------------------ + std::vector::const_iterator end() const + { + return parent->sections_.cend(); + } + + //------------------------------------------------------------------------------ + private: + elfio* parent; + } sections; + + //------------------------------------------------------------------------------ + friend class Segments; + class Segments + { + public: + //------------------------------------------------------------------------------ + explicit Segments( elfio* parent ) : parent( parent ) {} + + //------------------------------------------------------------------------------ + Elf_Half size() const + { + return static_cast( parent->segments_.size() ); + } + + //------------------------------------------------------------------------------ + segment* operator[]( unsigned int index ) const + { + return parent->segments_[index]; + } + + //------------------------------------------------------------------------------ + segment* add() { return parent->create_segment(); } + + //------------------------------------------------------------------------------ + std::vector::iterator begin() + { + return parent->segments_.begin(); + } + + //------------------------------------------------------------------------------ + std::vector::iterator end() + { + return parent->segments_.end(); + } + + //------------------------------------------------------------------------------ + std::vector::const_iterator begin() const + { + return parent->segments_.cbegin(); + } + + //------------------------------------------------------------------------------ + std::vector::const_iterator end() const + { + return parent->segments_.cend(); + } + + //------------------------------------------------------------------------------ + private: + elfio* parent; + } segments; + + //------------------------------------------------------------------------------ + private: + elf_header* header; + std::vector sections_; + std::vector segments_; + endianess_convertor convertor; + address_translator addr_translator; + + Elf_Xword current_file_pos; +}; + +} // namespace ELFIO + +#include "elfio_symbols.hpp" +#include "elfio_note.hpp" +#include "elfio_relocation.hpp" +#include "elfio_dynamic.hpp" +#include "elfio_array.hpp" +#include "elfio_modinfo.hpp" +#include "elfio_versym.hpp" + +#endif // ELFIO_HPP diff --git a/tools/elfio/elfio_array.hpp b/tools/elfio/elfio_array.hpp new file mode 100644 index 00000000000..9f5aa3e3fc1 --- /dev/null +++ b/tools/elfio/elfio_array.hpp @@ -0,0 +1,87 @@ +/* +Copyright (C) 2001-present by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELFIO_ARRAY_HPP +#define ELFIO_ARRAY_HPP + +#include + +namespace ELFIO { + +//------------------------------------------------------------------------------ +template class array_section_accessor_template +{ + public: + //------------------------------------------------------------------------------ + array_section_accessor_template( const elfio& elf_file, S* section ) + : elf_file( elf_file ), array_section( section ) + { + } + + //------------------------------------------------------------------------------ + Elf_Xword get_entries_num() const + { + Elf_Xword entry_size = sizeof( T ); + return array_section->get_size() / entry_size; + } + + //------------------------------------------------------------------------------ + bool get_entry( Elf_Xword index, Elf64_Addr& address ) const + { + if ( index >= get_entries_num() ) { // Is index valid + return false; + } + + const endianess_convertor& convertor = elf_file.get_convertor(); + + const T temp = *reinterpret_cast( array_section->get_data() + + index * sizeof( T ) ); + address = convertor( temp ); + + return true; + } + + //------------------------------------------------------------------------------ + void add_entry( Elf64_Addr address ) + { + const endianess_convertor& convertor = elf_file.get_convertor(); + + T temp = convertor( (T)address ); + array_section->append_data( reinterpret_cast( &temp ), + sizeof( temp ) ); + } + + private: + //------------------------------------------------------------------------------ + const elfio& elf_file; + S* array_section; +}; + +template +using array_section_accessor = array_section_accessor_template; +template +using const_array_section_accessor = + array_section_accessor_template; + +} // namespace ELFIO + +#endif // ELFIO_ARRAY_HPP diff --git a/tools/elfio/elfio_dump.hpp b/tools/elfio/elfio_dump.hpp new file mode 100644 index 00000000000..5b7d9508c3c --- /dev/null +++ b/tools/elfio/elfio_dump.hpp @@ -0,0 +1,1270 @@ +/* +Copyright (C) 2001-present by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELFIO_DUMP_HPP +#define ELFIO_DUMP_HPP + +#include +#include +#include +#include +#include +#include + +namespace ELFIO { + +static const struct class_table_t +{ + const char key; + const char* str; +} class_table[] = { + { ELFCLASS32, "ELF32" }, + { ELFCLASS64, "ELF64" }, +}; + +static const struct endian_table_t +{ + const char key; + const char* str; +} endian_table[] = { + { ELFDATANONE, "None" }, + { ELFDATA2LSB, "Little endian" }, + { ELFDATA2MSB, "Big endian" }, +}; + +static const struct version_table_t +{ + const Elf64_Word key; + const char* str; +} version_table[] = { + { EV_NONE, "None" }, + { EV_CURRENT, "Current" }, +}; + +static const struct type_table_t +{ + const Elf32_Half key; + const char* str; +} type_table[] = { + { ET_NONE, "No file type" }, { ET_REL, "Relocatable file" }, + { ET_EXEC, "Executable file" }, { ET_DYN, "Shared object file" }, + { ET_CORE, "Core file" }, +}; + +static const struct machine_table_t +{ + const Elf64_Half key; + const char* str; +} machine_table[] = { + { EM_NONE, "No machine" }, + { EM_M32, "AT&T WE 32100" }, + { EM_SPARC, "SUN SPARC" }, + { EM_386, "Intel 80386" }, + { EM_68K, "Motorola m68k family" }, + { EM_88K, "Motorola m88k family" }, + { EM_486, "Intel 80486// Reserved for future use" }, + { EM_860, "Intel 80860" }, + { EM_MIPS, "MIPS R3000 (officially, big-endian only)" }, + { EM_S370, "IBM System/370" }, + { EM_MIPS_RS3_LE, + "MIPS R3000 little-endian (Oct 4 1999 Draft) Deprecated" }, + { EM_res011, "Reserved" }, + { EM_res012, "Reserved" }, + { EM_res013, "Reserved" }, + { EM_res014, "Reserved" }, + { EM_PARISC, "HPPA" }, + { EM_res016, "Reserved" }, + { EM_VPP550, "Fujitsu VPP500" }, + { EM_SPARC32PLUS, "Sun's v8plus" }, + { EM_960, "Intel 80960" }, + { EM_PPC, "PowerPC" }, + { EM_PPC64, "64-bit PowerPC" }, + { EM_S390, "IBM S/390" }, + { EM_SPU, "Sony/Toshiba/IBM SPU" }, + { EM_res024, "Reserved" }, + { EM_res025, "Reserved" }, + { EM_res026, "Reserved" }, + { EM_res027, "Reserved" }, + { EM_res028, "Reserved" }, + { EM_res029, "Reserved" }, + { EM_res030, "Reserved" }, + { EM_res031, "Reserved" }, + { EM_res032, "Reserved" }, + { EM_res033, "Reserved" }, + { EM_res034, "Reserved" }, + { EM_res035, "Reserved" }, + { EM_V800, "NEC V800 series" }, + { EM_FR20, "Fujitsu FR20" }, + { EM_RH32, "TRW RH32" }, + { EM_MCORE, "Motorola M*Core // May also be taken by Fujitsu MMA" }, + { EM_RCE, "Old name for MCore" }, + { EM_ARM, "ARM" }, + { EM_OLD_ALPHA, "Digital Alpha" }, + { EM_SH, "Renesas (formerly Hitachi) / SuperH SH" }, + { EM_SPARCV9, "SPARC v9 64-bit" }, + { EM_TRICORE, "Siemens Tricore embedded processor" }, + { EM_ARC, "ARC Cores" }, + { EM_H8_300, "Renesas (formerly Hitachi) H8/300" }, + { EM_H8_300H, "Renesas (formerly Hitachi) H8/300H" }, + { EM_H8S, "Renesas (formerly Hitachi) H8S" }, + { EM_H8_500, "Renesas (formerly Hitachi) H8/500" }, + { EM_IA_64, "Intel IA-64 Processor" }, + { EM_MIPS_X, "Stanford MIPS-X" }, + { EM_COLDFIRE, "Motorola Coldfire" }, + { EM_68HC12, "Motorola M68HC12" }, + { EM_MMA, "Fujitsu Multimedia Accelerator" }, + { EM_PCP, "Siemens PCP" }, + { EM_NCPU, "Sony nCPU embedded RISC processor" }, + { EM_NDR1, "Denso NDR1 microprocesspr" }, + { EM_STARCORE, "Motorola Star*Core processor" }, + { EM_ME16, "Toyota ME16 processor" }, + { EM_ST100, "STMicroelectronics ST100 processor" }, + { EM_TINYJ, "Advanced Logic Corp. TinyJ embedded processor" }, + { EM_X86_64, "Advanced Micro Devices X86-64 processor" }, + { EM_PDSP, "Sony DSP Processor" }, + { EM_PDP10, "Digital Equipment Corp. PDP-10" }, + { EM_PDP11, "Digital Equipment Corp. PDP-11" }, + { EM_FX66, "Siemens FX66 microcontroller" }, + { EM_ST9PLUS, "STMicroelectronics ST9+ 8/16 bit microcontroller" }, + { EM_ST7, "STMicroelectronics ST7 8-bit microcontroller" }, + { EM_68HC16, "Motorola MC68HC16 Microcontroller" }, + { EM_68HC11, "Motorola MC68HC11 Microcontroller" }, + { EM_68HC08, "Motorola MC68HC08 Microcontroller" }, + { EM_68HC05, "Motorola MC68HC05 Microcontroller" }, + { EM_SVX, "Silicon Graphics SVx" }, + { EM_ST19, "STMicroelectronics ST19 8-bit cpu" }, + { EM_VAX, "Digital VAX" }, + { EM_CRIS, "Axis Communications 32-bit embedded processor" }, + { EM_JAVELIN, "Infineon Technologies 32-bit embedded cpu" }, + { EM_FIREPATH, "Element 14 64-bit DSP processor" }, + { EM_ZSP, "LSI Logic's 16-bit DSP processor" }, + { EM_MMIX, "Donald Knuth's educational 64-bit processor" }, + { EM_HUANY, "Harvard's machine-independent format" }, + { EM_PRISM, "SiTera Prism" }, + { EM_AVR, "Atmel AVR 8-bit microcontroller" }, + { EM_FR30, "Fujitsu FR30" }, + { EM_D10V, "Mitsubishi D10V" }, + { EM_D30V, "Mitsubishi D30V" }, + { EM_V850, "NEC v850" }, + { EM_M32R, "Renesas M32R (formerly Mitsubishi M32R)" }, + { EM_MN10300, "Matsushita MN10300" }, + { EM_MN10200, "Matsushita MN10200" }, + { EM_PJ, "picoJava" }, + { EM_OPENRISC, "OpenRISC 32-bit embedded processor" }, + { EM_ARC_A5, "ARC Cores Tangent-A5" }, + { EM_XTENSA, "Tensilica Xtensa Architecture" }, + { EM_VIDEOCORE, "Alphamosaic VideoCore processor" }, + { EM_TMM_GPP, "Thompson Multimedia General Purpose Processor" }, + { EM_NS32K, "National Semiconductor 32000 series" }, + { EM_TPC, "Tenor Network TPC processor" }, + { EM_SNP1K, "Trebia SNP 1000 processor" }, + { EM_ST200, "STMicroelectronics ST200 microcontroller" }, + { EM_IP2K, "Ubicom IP2022 micro controller" }, + { EM_MAX, "MAX Processor" }, + { EM_CR, "National Semiconductor CompactRISC" }, + { EM_F2MC16, "Fujitsu F2MC16" }, + { EM_MSP430, "TI msp430 micro controller" }, + { EM_BLACKFIN, "ADI Blackfin" }, + { EM_SE_C33, "S1C33 Family of Seiko Epson processors" }, + { EM_SEP, "Sharp embedded microprocessor" }, + { EM_ARCA, "Arca RISC Microprocessor" }, + { EM_UNICORE, "Microprocessor series from PKU-Unity Ltd. and MPRC of " + "Peking University" }, + { EM_EXCESS, "eXcess: 16/32/64-bit configurable embedded CPU" }, + { EM_DXP, "Icera Semiconductor Inc. Deep Execution Processor" }, + { EM_ALTERA_NIOS2, "Altera Nios II soft-core processor" }, + { EM_CRX, "National Semiconductor CRX" }, + { EM_XGATE, "Motorola XGATE embedded processor" }, + { EM_C166, "Infineon C16x/XC16x processor" }, + { EM_M16C, "Renesas M16C series microprocessors" }, + { EM_DSPIC30F, "Microchip Technology dsPIC30F Digital Signal Controller" }, + { EM_CE, "Freescale Communication Engine RISC core" }, + { EM_M32C, "Renesas M32C series microprocessors" }, + { EM_res121, "Reserved" }, + { EM_res122, "Reserved" }, + { EM_res123, "Reserved" }, + { EM_res124, "Reserved" }, + { EM_res125, "Reserved" }, + { EM_res126, "Reserved" }, + { EM_res127, "Reserved" }, + { EM_res128, "Reserved" }, + { EM_res129, "Reserved" }, + { EM_res130, "Reserved" }, + { EM_TSK3000, "Altium TSK3000 core" }, + { EM_RS08, "Freescale RS08 embedded processor" }, + { EM_res133, "Reserved" }, + { EM_ECOG2, "Cyan Technology eCOG2 microprocessor" }, + { EM_SCORE, "Sunplus Score" }, + { EM_SCORE7, "Sunplus S+core7 RISC processor" }, + { EM_DSP24, "New Japan Radio (NJR) 24-bit DSP Processor" }, + { EM_VIDEOCORE3, "Broadcom VideoCore III processor" }, + { EM_LATTICEMICO32, "RISC processor for Lattice FPGA architecture" }, + { EM_SE_C17, "Seiko Epson C17 family" }, + { EM_TI_C6000, "Texas Instruments TMS320C6000 DSP family" }, + { EM_TI_C2000, "Texas Instruments TMS320C2000 DSP family" }, + { EM_TI_C5500, "Texas Instruments TMS320C55x DSP family" }, + { EM_res143, "Reserved" }, + { EM_res144, "Reserved" }, + { EM_res145, "Reserved" }, + { EM_res146, "Reserved" }, + { EM_res147, "Reserved" }, + { EM_res148, "Reserved" }, + { EM_res149, "Reserved" }, + { EM_res150, "Reserved" }, + { EM_res151, "Reserved" }, + { EM_res152, "Reserved" }, + { EM_res153, "Reserved" }, + { EM_res154, "Reserved" }, + { EM_res155, "Reserved" }, + { EM_res156, "Reserved" }, + { EM_res157, "Reserved" }, + { EM_res158, "Reserved" }, + { EM_res159, "Reserved" }, + { EM_MMDSP_PLUS, "STMicroelectronics 64bit VLIW Data Signal Processor" }, + { EM_CYPRESS_M8C, "Cypress M8C microprocessor" }, + { EM_R32C, "Renesas R32C series microprocessors" }, + { EM_TRIMEDIA, "NXP Semiconductors TriMedia architecture family" }, + { EM_QDSP6, "QUALCOMM DSP6 Processor" }, + { EM_8051, "Intel 8051 and variants" }, + { EM_STXP7X, "STMicroelectronics STxP7x family" }, + { EM_NDS32, + "Andes Technology compact code size embedded RISC processor family" }, + { EM_ECOG1, "Cyan Technology eCOG1X family" }, + { EM_ECOG1X, "Cyan Technology eCOG1X family" }, + { EM_MAXQ30, "Dallas Semiconductor MAXQ30 Core Micro-controllers" }, + { EM_XIMO16, "New Japan Radio (NJR) 16-bit DSP Processor" }, + { EM_MANIK, "M2000 Reconfigurable RISC Microprocessor" }, + { EM_CRAYNV2, "Cray Inc. NV2 vector architecture" }, + { EM_RX, "Renesas RX family" }, + { EM_METAG, "Imagination Technologies META processor architecture" }, + { EM_MCST_ELBRUS, "MCST Elbrus general purpose hardware architecture" }, + { EM_ECOG16, "Cyan Technology eCOG16 family" }, + { EM_CR16, "National Semiconductor CompactRISC 16-bit processor" }, + { EM_ETPU, "Freescale Extended Time Processing Unit" }, + { EM_SLE9X, "Infineon Technologies SLE9X core" }, + { EM_L1OM, "Intel L1OM" }, + { EM_INTEL181, "Reserved by Intel" }, + { EM_INTEL182, "Reserved by Intel" }, + { EM_AARCH64, "ARM AArch64" }, + { EM_res184, "Reserved by ARM" }, + { EM_AVR32, "Atmel Corporation 32-bit microprocessor family" }, + { EM_STM8, "STMicroeletronics STM8 8-bit microcontroller" }, + { EM_TILE64, "Tilera TILE64 multicore architecture family" }, + { EM_TILEPRO, "Tilera TILEPro multicore architecture family" }, + { EM_MICROBLAZE, "Xilinx MicroBlaze 32-bit RISC soft processor core" }, + { EM_CUDA, "NVIDIA CUDA architecture " }, + { EM_TILEGX, "Tilera TILE-Gx multicore architecture family" }, + { EM_CLOUDSHIELD, "CloudShield architecture family" }, + { EM_COREA_1ST, "KIPO-KAIST Core-A 1st generation processor family" }, + { EM_COREA_2ND, "KIPO-KAIST Core-A 2nd generation processor family" }, + { EM_ARC_COMPACT2, "Synopsys ARCompact V2" }, + { EM_OPEN8, "Open8 8-bit RISC soft processor core" }, + { EM_RL78, "Renesas RL78 family" }, + { EM_VIDEOCORE5, "Broadcom VideoCore V processor" }, + { EM_78KOR, "Renesas 78KOR family" }, + { EM_56800EX, "Freescale 56800EX Digital Signal Controller (DSC)" }, + { EM_BA1, "Beyond BA1 CPU architecture" }, + { EM_BA2, "Beyond BA2 CPU architecture" }, + { EM_XCORE, "XMOS xCORE processor family" }, + { EM_MCHP_PIC, "Microchip 8-bit PIC(r) family" }, + { EM_INTEL205, "Reserved by Intel" }, + { EM_INTEL206, "Reserved by Intel" }, + { EM_INTEL207, "Reserved by Intel" }, + { EM_INTEL208, "Reserved by Intel" }, + { EM_INTEL209, "Reserved by Intel" }, + { EM_KM32, "KM211 KM32 32-bit processor" }, + { EM_KMX32, "KM211 KMX32 32-bit processor" }, + { EM_KMX16, "KM211 KMX16 16-bit processor" }, + { EM_KMX8, "KM211 KMX8 8-bit processor" }, + { EM_KVARC, "KM211 KVARC processor" }, + { EM_CDP, "Paneve CDP architecture family" }, + { EM_COGE, "Cognitive Smart Memory Processor" }, + { EM_COOL, "iCelero CoolEngine" }, + { EM_NORC, "Nanoradio Optimized RISC" }, + { EM_CSR_KALIMBA, "CSR Kalimba architecture family" }, + { EM_Z80, "Zilog Z80" }, + { EM_VISIUM, "Controls and Data Services VISIUMcore processor" }, + { EM_FT32, "FTDI Chip FT32 high performance 32-bit RISC architecture" }, + { EM_MOXIE, "Moxie processor family" }, + { EM_AMDGPU, "AMD GPU architecture" }, + { EM_RISCV, "RISC-V" }, + { EM_LANAI, "Lanai processor" }, + { EM_CEVA, "CEVA Processor Architecture Family" }, + { EM_CEVA_X2, "CEVA X2 Processor Family" }, + { EM_BPF, "Linux BPF – in-kernel virtual machine" }, + { EM_GRAPHCORE_IPU, "Graphcore Intelligent Processing Unit" }, + { EM_IMG1, "Imagination Technologies" }, + { EM_NFP, "Netronome Flow Processor (P)" }, + { EM_CSKY, "C-SKY processor family" }, + { EM_ARC_COMPACT3_64, "Synopsys ARCv2.3 64-bit" }, + { EM_MCS6502, "MOS Technology MCS 6502 processor" }, + { EM_ARC_COMPACT3, "Synopsys ARCv2.3 32-bit" }, + { EM_KVX, "Kalray VLIW core of the MPPA processor family" }, + { EM_65816, "WDC 65816/65C816" }, + { EM_LOONGARCH, "Loongson Loongarch" }, + { EM_KF32, "ChipON KungFu32" }, + { EM_MT, "Morpho Techologies MT processor" }, + { EM_ALPHA, "Alpha" }, + { EM_WEBASSEMBLY, "Web Assembly" }, + { EM_DLX, "OpenDLX" }, + { EM_XSTORMY16, "Sanyo XStormy16 CPU core" }, + { EM_IQ2000, "Vitesse IQ2000" }, + { EM_M32C_OLD, "M32C_OLD" }, + { EM_NIOS32, "Altera Nios" }, + { EM_CYGNUS_MEP, "Toshiba MeP Media Engine" }, + { EM_ADAPTEVA_EPIPHANY, "Adapteva EPIPHANY" }, + { EM_CYGNUS_FRV, "Fujitsu FR-V" }, + { EM_S12Z, "Freescale S12Z" }, +}; + +static const struct section_type_table_t +{ + const Elf64_Word key; + const char* str; +} section_type_table[] = { + { SHT_NULL, "NULL" }, + { SHT_PROGBITS, "PROGBITS" }, + { SHT_SYMTAB, "SYMTAB" }, + { SHT_STRTAB, "STRTAB" }, + { SHT_RELA, "RELA" }, + { SHT_HASH, "HASH" }, + { SHT_DYNAMIC, "DYNAMIC" }, + { SHT_NOTE, "NOTE" }, + { SHT_NOBITS, "NOBITS" }, + { SHT_REL, "REL" }, + { SHT_SHLIB, "SHLIB" }, + { SHT_DYNSYM, "DYNSYM" }, + { SHT_INIT_ARRAY, "INIT_ARRAY" }, + { SHT_FINI_ARRAY, "FINI_ARRAY" }, + { SHT_PREINIT_ARRAY, "PREINIT_ARRAY" }, + { SHT_GROUP, "GROUP" }, + { SHT_SYMTAB_SHNDX, "SYMTAB_SHNDX" }, + { SHT_GNU_ATTRIBUTES, "GNU_ATTRIBUTES" }, + { SHT_GNU_HASH, "GNU_HASH" }, + { SHT_GNU_LIBLIST, "GNU_LIBLIST" }, + { SHT_CHECKSUM, "CHECKSUM" }, + { SHT_LOSUNW, "LOSUNW" }, + { SHT_SUNW_move, "SUNW_move" }, + { SHT_SUNW_COMDAT, "SUNW_COMDAT" }, + { SHT_SUNW_syminfo, "SUNW_syminfo" }, + { SHT_GNU_verdef, "GNU_verdef" }, + { SHT_GNU_verneed, "GNU_verneed" }, + { SHT_GNU_versym, "GNU_versym" }, + +}; + +static const struct segment_type_table_t +{ + const Elf_Word key; + const char* str; +} segment_type_table[] = { + { PT_NULL, "NULL" }, + { PT_LOAD, "LOAD" }, + { PT_DYNAMIC, "DYNAMIC" }, + { PT_INTERP, "INTERP" }, + { PT_NOTE, "NOTE" }, + { PT_SHLIB, "SHLIB" }, + { PT_PHDR, "PHDR" }, + { PT_TLS, "TLS" }, + { PT_GNU_EH_FRAME, "GNU_EH_FRAME" }, + { PT_GNU_STACK, "GNU_STACK" }, + { PT_GNU_RELRO, "GNU_RELRO" }, + { PT_GNU_PROPERTY, "GNU_PROPERTY" }, + { PT_GNU_MBIND_LO, "GNU_MBIND_LO" }, + { PT_GNU_MBIND_HI, "GNU_MBIND_HI" }, + { PT_PAX_FLAGS, "PAX_FLAGS" }, + { PT_OPENBSD_RANDOMIZE, "OPENBSD_RANDOMIZE" }, + { PT_OPENBSD_WXNEEDED, "OPENBSD_WXNEEDED " }, + { PT_OPENBSD_BOOTDATA, "OPENBSD_BOOTDATA " }, + { PT_SUNWSTACK, "SUNWSTACK" }, +}; + +static const struct segment_flag_table_t +{ + const Elf_Word key; + const char* str; +} segment_flag_table[] = { + { 0, " " }, { 1, " E" }, { 2, " W " }, { 3, " WE" }, + { 4, "R " }, { 5, "R E" }, { 6, "RW " }, { 7, "RWE" }, +}; + +static const struct symbol_bind_t +{ + const Elf_Word key; + const char* str; +} symbol_bind_table[] = { + { STB_LOCAL, "LOCAL" }, { STB_GLOBAL, "GLOBAL" }, + { STB_WEAK, "WEAK" }, { STB_LOOS, "LOOS" }, + { STB_HIOS, "HIOS" }, { STB_MULTIDEF, "MULTIDEF" }, + { STB_LOPROC, "LOPROC" }, { STB_HIPROC, "HIPROC" }, +}; + +static const struct symbol_type_t +{ + const Elf_Word key; + const char* str; +} symbol_type_table[] = { + { STT_NOTYPE, "NOTYPE" }, { STT_OBJECT, "OBJECT" }, + { STT_FUNC, "FUNC" }, { STT_SECTION, "SECTION" }, + { STT_FILE, "FILE" }, { STT_COMMON, "COMMON" }, + { STT_TLS, "TLS" }, { STT_LOOS, "LOOS" }, + { STT_HIOS, "HIOS" }, { STT_LOPROC, "LOPROC" }, + { STT_HIPROC, "HIPROC" }, +}; + +static const struct dynamic_tag_t +{ + const Elf_Word key; + const char* str; +} dynamic_tag_table[] = { + { DT_NULL, "NULL" }, + { DT_NEEDED, "NEEDED" }, + { DT_PLTRELSZ, "PLTRELSZ" }, + { DT_PLTGOT, "PLTGOT" }, + { DT_HASH, "HASH" }, + { DT_STRTAB, "STRTAB" }, + { DT_SYMTAB, "SYMTAB" }, + { DT_RELA, "RELA" }, + { DT_RELASZ, "RELASZ" }, + { DT_RELAENT, "RELAENT" }, + { DT_STRSZ, "STRSZ" }, + { DT_SYMENT, "SYMENT" }, + { DT_INIT, "INIT" }, + { DT_FINI, "FINI" }, + { DT_SONAME, "SONAME" }, + { DT_RPATH, "RPATH" }, + { DT_SYMBOLIC, "SYMBOLIC" }, + { DT_REL, "REL" }, + { DT_RELSZ, "RELSZ" }, + { DT_RELENT, "RELENT" }, + { DT_PLTREL, "PLTREL" }, + { DT_DEBUG, "DEBUG" }, + { DT_TEXTREL, "TEXTREL" }, + { DT_JMPREL, "JMPREL" }, + { DT_BIND_NOW, "BIND_NOW" }, + { DT_INIT_ARRAY, "INIT_ARRAY" }, + { DT_FINI_ARRAY, "FINI_ARRAY" }, + { DT_INIT_ARRAYSZ, "INIT_ARRAYSZ" }, + { DT_FINI_ARRAYSZ, "FINI_ARRAYSZ" }, + { DT_RUNPATH, "RUNPATH" }, + { DT_FLAGS, "FLAGS" }, + { DT_ENCODING, "ENCODING" }, + { DT_PREINIT_ARRAY, "PREINIT_ARRAY" }, + { DT_PREINIT_ARRAYSZ, "PREINIT_ARRAYSZ" }, + { DT_MAXPOSTAGS, "MAXPOSTAGS" }, + { DT_GNU_HASH, "GNU_HASH" }, + { DT_VERSYM, "VERSYM" }, + { DT_FLAGS_1, "FLAGS_1" }, + { DT_VERNEED, "VERNEED" }, + { DT_VERNEEDNUM, "VERNEEDNUM" }, +}; + +// clang-format off +static const struct note_tag_t +{ + struct note_values_t + { + Elf64_Word type; + std::string type_str; + std::string description; + }; + std::string name; + std::vector values; +} note_tag_table[] = { + { "", + { { NT_PRSTATUS, "NT_PRSTATUS", "prstatus struct" }, + { NT_FPREGSET, "NT_FPREGSET", "fpregset struct" }, + { NT_PRPSINFO, "NT_PRPSINFO", "prpsinfo struct" }, + { NT_TASKSTRUCT, "NT_TASKSTRUCT", "task struct" }, + { NT_AUXV, "NT_AUXV", "Elfxx_auxv_t" }, + { NT_PSTATUS, "NT_PSTATUS", "pstatus struct" }, + { NT_FPREGS, "NT_FPREGS", "fpregset struct" }, + { NT_PSINFO, "NT_PSINFO", "psinfo struct" }, + { NT_LWPSTATUS, "NT_LWPSTATUS", "lwpstatus_t struct" }, + { NT_LWPSINFO, "NT_LWPSINFO", "lwpsinfo_t struct" }, + { NT_WIN32PSTATUS, "NT_WIN32PSTATUS", "win32_pstatus struct" }, + } }, + { "LINUX", + { { NT_PRXFPREG, "NT_PRXFPREG", "Contains a user_xfpregs_struct;" }, + { NT_PPC_VMX, "NT_PPC_VMX", "PowerPC Altivec/VMX registers" }, + { NT_PPC_VSX, "NT_PPC_VSX", "PowerPC VSX registers" }, + { NT_PPC_TAR, "NT_PPC_TAR", "PowerPC Target Address Register" }, + { NT_PPC_PPR, "NT_PPC_PPR", "PowerPC Program Priority Register" }, + { NT_PPC_DSCR, "NT_PPC_DSCR", "PowerPC Data Stream Control Register" }, + { NT_PPC_EBB, "NT_PPC_EBB", "PowerPC Event Based Branch Registers" }, + { NT_PPC_PMU, "NT_PPC_PMU", "PowerPC Performance Monitor Registers" }, + { NT_PPC_TM_CGPR, "NT_PPC_TM_CGPR", "PowerPC TM checkpointed GPR Registers" }, + { NT_PPC_TM_CFPR, "NT_PPC_TM_CFPR", "PowerPC TM checkpointed FPR Registers" }, + { NT_PPC_TM_CVMX, "NT_PPC_TM_CVMX", "PowerPC TM checkpointed VMX Registers" }, + { NT_PPC_TM_CVSX, "NT_PPC_TM_CVSX", "PowerPC TM checkpointed VSX Registers" }, + { NT_PPC_TM_SPR, "NT_PPC_TM_SPR", "PowerPC TM Special Purpose Registers" }, + { NT_PPC_TM_CTAR, "NT_PPC_TM_CTAR", "PowerPC TM checkpointed TAR" }, + { NT_PPC_TM_CPPR, "NT_PPC_TM_CPPR", "PowerPC TM checkpointed PPR" }, + { NT_PPC_TM_CDSCR, "NT_PPC_TM_CDSCR", "PowerPC TM checkpointed Data SCR" }, + { NT_386_TLS, "NT_386_TLS", "x86 TLS information" }, + { NT_386_IOPERM, "NT_386_IOPERM", "x86 io permissions" }, + { NT_X86_XSTATE, "NT_X86_XSTATE", "x86 XSAVE extended state" }, + { NT_X86_CET, "NT_X86_CET", "x86 CET state" }, + { NT_S390_HIGH_GPRS, "NT_S390_HIGH_GPRS", "S/390 upper halves of GPRs " }, + { NT_S390_TIMER, "NT_S390_TIMER", "S390 timer" }, + { NT_S390_TODCMP, "NT_S390_TODCMP", "S390 TOD clock comparator" }, + { NT_S390_TODPREG, "NT_S390_TODPREG", "S390 TOD programmable register" }, + { NT_S390_CTRS, "NT_S390_CTRS", "S390 control registers" }, + { NT_S390_PREFIX, "NT_S390_PREFIX", "S390 prefix register" }, + { NT_S390_LAST_BREAK, "NT_S390_LAST_BREAK", "S390 breaking event address" }, + { NT_S390_SYSTEM_CALL, "NT_S390_SYSTEM_CALL", "S390 system call restart data" }, + { NT_S390_TDB, "NT_S390_TDB", "S390 transaction diagnostic block" }, + { NT_S390_VXRS_LOW, "NT_S390_VXRS_LOW", "S390 vector registers 0-15 upper half" }, + { NT_S390_VXRS_HIGH, "NT_S390_VXRS_HIGH", "S390 vector registers 16-31" }, + { NT_S390_GS_CB, "NT_S390_GS_CB", "s390 guarded storage registers" }, + { NT_S390_GS_BC, "NT_S390_GS_BC", "s390 guarded storage broadcast control block" }, + { NT_ARM_VFP, "NT_ARM_VFP", "ARM VFP registers" }, + { NT_ARM_TLS, "NT_ARM_TLS", "AArch TLS registers" }, + { NT_ARM_HW_BREAK, "NT_ARM_HW_BREAK", "AArch hardware breakpoint registers" }, + { NT_ARM_HW_WATCH, "NT_ARM_HW_WATCH", "AArch hardware watchpoint registers" }, + { NT_ARM_SVE, "NT_ARM_SVE", "AArch SVE registers. " }, + { NT_ARM_PAC_MASK, "NT_ARM_PAC_MASK", "AArch pointer authentication code masks" }, + { NT_ARM_PACA_KEYS, "NT_ARM_PACA_KEYS", "ARM pointer authentication address keys" }, + { NT_ARM_PACG_KEYS, "NT_ARM_PACG_KEYS", "ARM pointer authentication generic keys" }, + { NT_ARM_TAGGED_ADDR_CTRL, "NT_ARM_TAGGED_ADDR_CTRL", "AArch64 tagged address control (prctl())" }, + { NT_ARM_PAC_ENABLED_KEYS, "NT_ARM_PAC_ENABLED_KEYS", "AArch64 pointer authentication enabled keys (prctl())" }, + { NT_ARC_V2, "NT_ARC_V2", "ARC HS accumulator/extra registers. " }, + { NT_LARCH_CPUCFG, "NT_LARCH_CPUCFG", "LoongArch CPU config registers" }, + { NT_LARCH_CSR, "NT_LARCH_CSR", "LoongArch Control State Registers" }, + { NT_LARCH_LSX, "NT_LARCH_LSX", "LoongArch SIMD eXtension registers" }, + { NT_LARCH_LASX, "NT_LARCH_LASX", "LoongArch Advanced SIMD eXtension registers" }, + { NT_RISCV_CSR, "NT_RISCV_CSR", "RISC-V Control and Status Registers" }, + } }, + { "CORE", + { { NT_LARCH_LBT, "NT_LARCH_LBT", "LoongArch Binary Translation registers" } + } }, + { "FreeBSD", + { { NT_FREEBSD_THRMISC, "NT_FREEBSD_THRMISC", "Thread miscellaneous info." }, + { NT_FREEBSD_PROCSTAT_PROC, "NT_FREEBSD_PROCSTAT_PROC", "Procstat proc data." }, + { NT_FREEBSD_PROCSTAT_FILES, "NT_FREEBSD_PROCSTAT_FILES", "Procstat files data." }, + { NT_FREEBSD_PROCSTAT_VMMAP, "NT_FREEBSD_PROCSTAT_VMMAP", "Procstat vmmap data." }, + { NT_FREEBSD_PROCSTAT_GROUPS, "NT_FREEBSD_PROCSTAT_GROUPS", "Procstat groups data." }, + { NT_FREEBSD_PROCSTAT_UMASK, "NT_FREEBSD_PROCSTAT_UMASK", "Procstat umask data." }, + { NT_FREEBSD_PROCSTAT_RLIMIT, "NT_FREEBSD_PROCSTAT_RLIMIT", "Procstat rlimit data." }, + { NT_FREEBSD_PROCSTAT_OSREL, "NT_FREEBSD_PROCSTAT_OSREL", "Procstat osreldate data." }, + { NT_FREEBSD_PROCSTAT_PSSTRINGS, "NT_FREEBSD_PROCSTAT_PSSTRINGS", "Procstat ps_strings data." }, + { NT_FREEBSD_PROCSTAT_AUXV, "NT_FREEBSD_PROCSTAT_AUXV", "Procstat auxv data." }, + { NT_FREEBSD_PTLWPINFO, "NT_FREEBSD_PTLWPINFO", "Thread ptrace miscellaneous info." }, + } }, + { "NetBSD-CORE", + { { NT_NETBSDCORE_PROCINFO, "NT_NETBSDCORE_PROCINFO", "Has a struct procinfo" }, + { NT_NETBSDCORE_AUXV, "NT_NETBSDCORE_AUXV", "Has auxv data" }, + { NT_NETBSDCORE_LWPSTATUS, "NT_NETBSDCORE_LWPSTATUS", "Has LWPSTATUS data" }, + { NT_NETBSDCORE_FIRSTMACH, "NT_NETBSDCORE_FIRSTMACH", "start of machdep note types" }, + } }, + { "OpenBSD", + { { NT_OPENBSD_PROCINFO, "NT_OPENBSD_PROCINFO", "" }, + { NT_OPENBSD_AUXV, "NT_OPENBSD_AUXV", "" }, + { NT_OPENBSD_REGS, "NT_OPENBSD_REGS", "" }, + { NT_OPENBSD_FPREGS, "NT_OPENBSD_FPREGS", "" }, + { NT_OPENBSD_XFPREGS, "NT_OPENBSD_XFPREGS", "" }, + { NT_OPENBSD_WCOOKIE, "NT_OPENBSD_WCOOKIE", "" }, + } }, + { "SPU", + { { NT_SPU, "NT_SPU", "" } + } }, + { "GNU", + { + { NT_GNU_ABI_TAG, "NT_GNU_ABI_TAG", "GNU ABI tag" }, + { NT_GNU_HWCAP, "NT_GNU_HWCAP", "Used by ld.so and kernel vDSO" }, + { NT_GNU_BUILD_ID, "NT_GNU_BUILD_ID", "Build ID of the binary" }, + { NT_GNU_GOLD_VERSION, "NT_GNU_GOLD_VERSION", "Version of GNU gold used to link the binary" }, + { NT_GNU_PROPERTY_TYPE_0, "NT_GNU_PROPERTY_TYPE_0", "Property type 0" }, + // { NT_GNU_PROPERTY_TYPE_1, "NT_GNU_PROPERTY_TYPE_1", "Property type 1" }, + // { NT_GNU_PROPERTY_TYPE_2, "NT_GNU_PROPERTY_TYPE_2", "Property type 2" }, + // { NT_GNU_PROPERTY_TYPE_3, "NT_GNU_PROPERTY_TYPE_3", "Property type 3" }, + // { NT_GNU_PROPERTY_TYPE_4, "NT_GNU_PROPERTY_TYPE_4", "Property type 4" }, + // { NT_GNU_PROPERTY_TYPE_5, "NT_GNU_PROPERTY_TYPE_5", "Property type 5" }, + // { NT_GNU_PROPERTY_TYPE_6, "NT_GNU_PROPERTY_TYPE_6", "Property type 6" }, + // { NT_GNU_PROPERTY_TYPE_7, "NT_GNU_PROPERTY_TYPE_7", "Property type 7" }, + // { NT_GNU_PROPERTY_TYPE_8, "NT_GNU_PROPERTY_TYPE_8", "Property type 8" }, + // { NT_GNU_PROPERTY_TYPE_9, "NT_GNU_PROPERTY_TYPE_9", "Property type 9" }, + // { NT_GNU_PROPERTY_TYPE_10, "NT_GNU_PROPERTY_TYPE_10", "Property type 10" }, + // { NT_GNU_PROPERTY_TYPE_11, "NT_GNU_PROPERTY_TYPE_11", "Property type 11" }, + // { NT_GNU_PROPERTY_TYPE_12, "NT_GNU_PROPERTY_TYPE_12", "Property type 12" }, + // { NT_GNU_PROPERTY_TYPE_13, "NT_GNU_PROPERTY_TYPE_13", "Property type 13" }, + // { NT_GNU_PROPERTY_TYPE_14, "NT_GNU_PROPERTY_TYPE_14", "Property type 14" }, + } }, + // { "SOLARIS", + // { { NT_SOLARIS_AUXV, "NT_SOLARIS_AUXV", "" } + // } }, + // { "AIX", + // { { NT_AIX_AUXV, "NT_AIX_AUXV", "" } + // } }, + // { "IRIX", + // { { NT_IRIX_FPREGS, "NT_IRIX_FPREGS", "" } + // } }, +}; +// clang-format on + +#define NT_LARCH_LBT 0xa04 /* LoongArch Binary Translation registers */ + /* note name must be "CORE". */ + +static const ELFIO::Elf_Xword MAX_DATA_ENTRIES = 64; + +//------------------------------------------------------------------------------ +class dump +{ +#define DUMP_DEC_FORMAT( width ) \ + std::setw( width ) << std::setfill( ' ' ) << std::dec << std::right +#define DUMP_HEX0x_FORMAT( width ) \ + "0x" << std::setw( width ) << std::setfill( '0' ) << std::hex << std::right +#define DUMP_HEX_FORMAT( width ) \ + std::setw( width ) << std::setfill( '0' ) << std::hex << std::right +#define DUMP_STR_FORMAT( width ) \ + std::setw( width ) << std::setfill( ' ' ) << std::hex << std::left + + public: + //------------------------------------------------------------------------------ + static void header( std::ostream& out, const elfio& reader ) + { + if ( !reader.get_header_size() ) { + return; + } + out << "ELF Header" << std::endl + << std::endl + << " Class: " << str_class( reader.get_class() ) << std::endl + << " Encoding: " << str_endian( reader.get_encoding() ) + << std::endl + << " ELFVersion: " << str_version( reader.get_elf_version() ) + << std::endl + << " Type: " << str_type( reader.get_type() ) << std::endl + << " Machine: " << str_machine( reader.get_machine() ) + << std::endl + << " Version: " << str_version( reader.get_version() ) + << std::endl + << " Entry: " + << "0x" << std::hex << reader.get_entry() << std::endl + << " Flags: " + << "0x" << std::hex << reader.get_flags() << std::endl + << std::endl; + } + + //------------------------------------------------------------------------------ + static void section_headers( std::ostream& out, const elfio& reader ) + { + Elf_Half n = reader.sections.size(); + + if ( n == 0 ) { + return; + } + + out << "Section Headers:" << std::endl; + if ( reader.get_class() == ELFCLASS32 ) { // Output for 32-bit + out << "[ Nr ] Type Addr Size ES Flg " + "Lk Inf Al Name" + << std::endl; + } + else { // Output for 64-bit + out << "[ Nr ] Type Addr Size " + " Offset Flg" + << std::endl + << " ES Lk Inf Al Name" << std::endl; + } + + for ( Elf_Half i = 0; i < n; ++i ) { // For all sections + section* sec = reader.sections[i]; + section_header( out, i, sec, reader.get_class() ); + } + + out << "Key to Flags: W (write), A (alloc), X (execute)\n\n" + << std::endl; + } + + //------------------------------------------------------------------------------ + static void section_header( std::ostream& out, + Elf_Half no, + const section* sec, + unsigned char elf_class ) + { + std::ios_base::fmtflags original_flags = out.flags(); + + // clang-format off + if ( elf_class == ELFCLASS32 ) { // Output for 32-bit + out << "[" << DUMP_DEC_FORMAT( 5 ) << no << "] " + << DUMP_STR_FORMAT( 17 ) << str_section_type( sec->get_type() ) + << " " << DUMP_HEX0x_FORMAT( 8 ) << sec->get_address() << " " + << DUMP_HEX0x_FORMAT( 8 ) << sec->get_size() << " " + << DUMP_HEX0x_FORMAT( 2 ) << sec->get_entry_size() << " " + << DUMP_STR_FORMAT( 3 ) << section_flags( sec->get_flags() ) + << " " << DUMP_HEX0x_FORMAT( 2 ) << sec->get_link() << " " + << DUMP_HEX0x_FORMAT( 3 ) << sec->get_info() << " " + << DUMP_HEX0x_FORMAT( 2 ) << sec->get_addr_align() << " " + << DUMP_STR_FORMAT( 17 ) << sec->get_name() << " " << std::endl; + } + else { // Output for 64-bit + out << "[" << DUMP_DEC_FORMAT( 5 ) << no << "] " + << DUMP_STR_FORMAT( 17 ) << str_section_type( sec->get_type() ) << " " + << DUMP_HEX0x_FORMAT( 16 ) << sec->get_address() << " " + << DUMP_HEX0x_FORMAT( 16 ) << sec->get_size() << " " + << DUMP_HEX0x_FORMAT( 8 ) << sec->get_offset() << " " + << DUMP_STR_FORMAT( 3) << section_flags( sec->get_flags() ) + << std::endl + << DUMP_STR_FORMAT( 8 ) << " " + << DUMP_HEX0x_FORMAT( 4 ) << sec->get_entry_size() << " " + << DUMP_HEX0x_FORMAT( 4 ) << sec->get_link() << " " + << DUMP_HEX0x_FORMAT( 4 ) << sec->get_info() << " " + << DUMP_HEX0x_FORMAT( 4 ) << sec->get_addr_align() << " " + << DUMP_STR_FORMAT( 17 ) << sec->get_name() + << std::endl; + } + // clang-format on + + out.flags( original_flags ); + + return; + } + + //------------------------------------------------------------------------------ + static void segment_headers( std::ostream& out, const elfio& reader ) + { + Elf_Half n = reader.segments.size(); + if ( n == 0 ) { + return; + } + + out << "Program Headers:" << std::endl; + if ( reader.get_class() == ELFCLASS32 ) { // Output for 32-bit + out << "[ Nr ] Type VirtAddr PhysAddr FileSize " + "Mem.Size Flags Align" + << std::endl; + } + else { // Output for 64-bit + out << "[ Nr ] Type Offset VirtAddr " + " PhysAddr" + + << std::endl + << " FileSize MemSize " + " Flags Align" + << std::endl; + } + + for ( Elf_Half i = 0; i < n; ++i ) { + segment* seg = reader.segments[i]; + segment_header( out, i, seg, reader.get_class() ); + } + + out << std::endl; + } + + //------------------------------------------------------------------------------ + static void segment_header( std::ostream& out, + Elf_Half no, + const segment* seg, + unsigned int elf_class ) + { + std::ios_base::fmtflags original_flags = out.flags(); + // clang-format off + if ( elf_class == ELFCLASS32 ) { // Output for 32-bit + out << "[" << DUMP_DEC_FORMAT( 5 ) << no << "] " + << DUMP_STR_FORMAT( 14 ) << str_segment_type( seg->get_type() ) + << " " << DUMP_HEX0x_FORMAT( 8 ) << seg->get_virtual_address() + << " " << DUMP_HEX0x_FORMAT( 8 ) << seg->get_physical_address() + << " " << DUMP_HEX0x_FORMAT( 8 ) << seg->get_file_size() << " " + << DUMP_HEX0x_FORMAT( 8 ) << seg->get_memory_size() << " " + << DUMP_STR_FORMAT( 8 ) << str_segment_flag( seg->get_flags() ) + << " " << DUMP_HEX0x_FORMAT( 8 ) << seg->get_align() << " " + << std::endl; + } + else { // Output for 64-bit + out << "[" << DUMP_DEC_FORMAT( 5 ) << no << "] " + << DUMP_STR_FORMAT( 14 ) << str_segment_type( seg->get_type() ) << " " + << DUMP_HEX0x_FORMAT( 16 ) << seg->get_offset() << " " + << DUMP_HEX0x_FORMAT( 16 ) << seg->get_virtual_address() << " " + << DUMP_HEX0x_FORMAT( 16 ) << seg->get_physical_address() + << std::endl + << DUMP_STR_FORMAT( 23 ) << " " + << DUMP_HEX0x_FORMAT( 16 ) << seg->get_file_size() << " " + << DUMP_HEX0x_FORMAT( 16 ) << seg->get_memory_size() << " " + << DUMP_STR_FORMAT( 3 ) << str_segment_flag( seg->get_flags() ) << " " + << DUMP_HEX0x_FORMAT( 1 ) << seg->get_align() + << std::endl; + } + // clang-format on + + out.flags( original_flags ); + } + + //------------------------------------------------------------------------------ + static void symbol_tables( std::ostream& out, const elfio& reader ) + { + Elf_Half n = reader.sections.size(); + for ( Elf_Half i = 0; i < n; ++i ) { // For all sections + section* sec = reader.sections[i]; + if ( SHT_SYMTAB == sec->get_type() || + SHT_DYNSYM == sec->get_type() ) { + symbol_section_accessor symbols( reader, sec ); + + Elf_Xword sym_no = symbols.get_symbols_num(); + if ( sym_no > 0 ) { + out << "Symbol table (" << sec->get_name() << ")" + << std::endl; + if ( reader.get_class() == + ELFCLASS32 ) { // Output for 32-bit + out << "[ Nr ] Value Size Type Bind " + " Sect Name" + << std::endl; + } + else { // Output for 64-bit + out << "[ Nr ] Value Size " + "Type Bind Sect" + << std::endl + << " Name" << std::endl; + } + for ( Elf_Xword i = 0; i < sym_no; ++i ) { + std::string name; + Elf64_Addr value = 0; + Elf_Xword size = 0; + unsigned char bind = 0; + unsigned char type = 0; + Elf_Half section = 0; + unsigned char other = 0; + symbols.get_symbol( i, name, value, size, bind, type, + section, other ); + symbol_table( out, i, name, value, size, bind, type, + section, reader.get_class() ); + } + + out << std::endl; + } + } + } + } + + //------------------------------------------------------------------------------ + static void symbol_table( std::ostream& out, + Elf_Xword no, + std::string& name, + Elf64_Addr value, + Elf_Xword size, + unsigned char bind, + unsigned char type, + Elf_Half section, + unsigned int elf_class ) + { + std::ios_base::fmtflags original_flags = out.flags(); + + if ( elf_class == ELFCLASS32 ) { // Output for 32-bit + out << "[" << DUMP_DEC_FORMAT( 5 ) << no << "] " + << DUMP_HEX0x_FORMAT( 8 ) << value << " " + << DUMP_HEX0x_FORMAT( 8 ) << size << " " << DUMP_STR_FORMAT( 7 ) + << str_symbol_type( type ) << " " << DUMP_STR_FORMAT( 8 ) + << str_symbol_bind( bind ) << " " << DUMP_DEC_FORMAT( 5 ) + << section << " " << DUMP_STR_FORMAT( 1 ) << name << " " + << std::endl; + } + else { // Output for 64-bit + out << "[" << DUMP_DEC_FORMAT( 5 ) << no << "] " + << DUMP_HEX0x_FORMAT( 16 ) << value << " " + << DUMP_HEX0x_FORMAT( 16 ) << size << " " + << DUMP_STR_FORMAT( 7 ) << str_symbol_type( type ) << " " + << DUMP_STR_FORMAT( 8 ) << str_symbol_bind( bind ) << " " + << DUMP_DEC_FORMAT( 5 ) << section << " " << std::endl + << " " << DUMP_STR_FORMAT( 1 ) << name << " " + << std::endl; + } + + out.flags( original_flags ); + } + + //------------------------------------------------------------------------------ + static void notes( std::ostream& out, const elfio& reader ) + { + Elf_Half no = reader.sections.size(); + for ( Elf_Half i = 0; i < no; ++i ) { // For all sections + section* sec = reader.sections[i]; + if ( SHT_NOTE == sec->get_type() ) { // Look at notes + note_section_accessor notes( reader, sec ); + Elf_Word no_notes = notes.get_notes_num(); + if ( no > 0 ) { + out << "Note section (" << sec->get_name() << ")" + << std::endl + << " No Name Data size Description" + << std::endl; + for ( Elf_Word j = 0; j < no_notes; ++j ) { // For all notes + Elf_Word type; + std::string name; + void* desc; + Elf_Word descsz; + + if ( notes.get_note( j, type, name, desc, descsz ) ) { + // 'name' usually contains \0 at the end. Remove it + name = name.c_str(); + note( out, j, type, name, desc, descsz ); + out << std::endl; + } + } + + out << std::endl; + } + } + } + + no = reader.segments.size(); + for ( Elf_Half i = 0; i < no; ++i ) { // For all segments + segment* seg = reader.segments[i]; + if ( PT_NOTE == seg->get_type() ) { // Look at notes + note_segment_accessor notes( reader, seg ); + Elf_Word no_notes = notes.get_notes_num(); + if ( no > 0 ) { + out << "Note segment (" << i << ")" + << std::endl + << " No Name Data size Description" + << std::endl; + for ( Elf_Word j = 0; j < no_notes; ++j ) { // For all notes + Elf_Word type; + std::string name; + void* desc; + Elf_Word descsz; + + if ( notes.get_note( j, type, name, desc, descsz ) ) { + // 'name' usually contains \0 at the end. Remove it + name = name.c_str(); + note( out, j, type, name, desc, descsz ); + out << std::endl; + } + } + + out << std::endl; + } + } + } + } + + //------------------------------------------------------------------------------ + static void note( std::ostream& out, + int no, + Elf_Word type, + const std::string& name, + void* desc, + Elf_Word descsz ) + { + out << " [" << DUMP_DEC_FORMAT( 2 ) << no << "] "; + + const note_tag_t* name_group = std::end( note_tag_table ); + std::vector::const_iterator type_value; + + name_group = std::find_if( + std::begin( note_tag_table ), std::end( note_tag_table ), + [&name]( const note_tag_t& entry ) { return entry.name == name; } ); + if ( name_group != std::end( note_tag_table ) ) { + type_value = std::find_if( + name_group->values.begin(), name_group->values.end(), + [&type]( const note_tag_t::note_values_t& e ) { + return e.type == type; + } ); + } + + if ( name_group != std::end( note_tag_table ) && + type_value != name_group->values.end() ) { + out << DUMP_STR_FORMAT( 12 ) << name_group->name << " " + << DUMP_HEX0x_FORMAT( 8 ) << descsz << " " + << type_value->type_str << " (" << type_value->description + << ")"; + } + else { + out << DUMP_STR_FORMAT( 12 ) << name << " " + << DUMP_HEX0x_FORMAT( 8 ) << descsz << " " + << DUMP_HEX0x_FORMAT( 8 ) << type; + } + + if ( descsz != 0 ) { + for ( Elf_Word i = 0; i < descsz; ++i ) { + if ( i % 16 == 0 ) { + out << std::endl << " "; + } + out << DUMP_HEX_FORMAT( 2 ) + << (uint32_t)( (uint8_t*)( desc ) )[i]; + } + } + } + + //------------------------------------------------------------------------------ + static void modinfo( std::ostream& out, const elfio& reader ) + { + Elf_Half no = reader.sections.size(); + for ( Elf_Half i = 0; i < no; ++i ) { // For all sections + section* sec = reader.sections[i]; + if ( ".modinfo" == sec->get_name() ) { // Look for the section + out << "Section .modinfo" << std::endl; + + const_modinfo_section_accessor modinfo( sec ); + for ( Elf_Word i = 0; i < modinfo.get_attribute_num(); i++ ) { + std::string field; + std::string value; + if ( modinfo.get_attribute( i, field, value ) ) { + out << " " << std::setw( 20 ) << field + << std::setw( 0 ) << " = " << value << std::endl; + } + } + + out << std::endl; + break; + } + } + } + + //------------------------------------------------------------------------------ + static void dynamic_tags( std::ostream& out, const elfio& reader ) + { + Elf_Half n = reader.sections.size(); + for ( Elf_Half i = 0; i < n; ++i ) { // For all sections + section* sec = reader.sections[i]; + if ( SHT_DYNAMIC == sec->get_type() ) { + dynamic_section_accessor dynamic( reader, sec ); + + Elf_Xword dyn_no = dynamic.get_entries_num(); + if ( dyn_no > 0 ) { + out << "Dynamic section (" << sec->get_name() << ")" + << std::endl; + out << "[ Nr ] Tag Name/Value" << std::endl; + for ( Elf_Xword i = 0; i < dyn_no; ++i ) { + Elf_Xword tag = 0; + Elf_Xword value = 0; + std::string str; + dynamic.get_entry( i, tag, value, str ); + dynamic_tag( out, i, tag, value, str, + reader.get_class() ); + if ( DT_NULL == tag ) { + break; + } + } + + out << std::endl; + } + } + } + } + + //------------------------------------------------------------------------------ + static void dynamic_tag( std::ostream& out, + Elf_Xword no, + Elf_Xword tag, + Elf_Xword value, + std::string str, + unsigned int /*elf_class*/ ) + { + out << "[" << DUMP_DEC_FORMAT( 5 ) << no << "] " + << DUMP_STR_FORMAT( 16 ) << str_dynamic_tag( tag ) << " "; + if ( str.empty() ) { + out << DUMP_HEX0x_FORMAT( 16 ) << value << " "; + } + else { + out << DUMP_STR_FORMAT( 32 ) << str << " "; + } + out << std::endl; + } + + //------------------------------------------------------------------------------ + static void section_data( std::ostream& out, const section* sec ) + { + std::ios_base::fmtflags original_flags = out.flags(); + + out << sec->get_name() << std::endl; + const char* pdata = sec->get_data(); + if ( pdata ) { + ELFIO::Elf_Xword i; + for ( i = 0; i < std::min( sec->get_size(), MAX_DATA_ENTRIES ); + ++i ) { + if ( i % 16 == 0 ) { + out << "[" << DUMP_HEX0x_FORMAT( 8 ) << i << "]"; + } + + out << " " << DUMP_HEX0x_FORMAT( 2 ) + << ( pdata[i] & 0x000000FF ); + + if ( i % 16 == 15 ) { + out << std::endl; + } + } + if ( i % 16 != 0 ) { + out << std::endl; + } + + out.flags( original_flags ); + } + + return; + } + + //------------------------------------------------------------------------------ + static void section_datas( std::ostream& out, const elfio& reader ) + { + Elf_Half n = reader.sections.size(); + + if ( n == 0 ) { + return; + } + + out << "Section Data:" << std::endl; + + for ( Elf_Half i = 1; i < n; ++i ) { // For all sections + section* sec = reader.sections[i]; + if ( sec->get_type() == SHT_NOBITS ) { + continue; + } + section_data( out, sec ); + } + + out << std::endl; + } + + //------------------------------------------------------------------------------ + static void + segment_data( std::ostream& out, Elf_Half no, const segment* seg ) + { + std::ios_base::fmtflags original_flags = out.flags(); + + out << "Segment # " << no << std::endl; + const char* pdata = seg->get_data(); + if ( pdata ) { + ELFIO::Elf_Xword i; + for ( i = 0; i < std::min( seg->get_file_size(), MAX_DATA_ENTRIES ); + ++i ) { + if ( i % 16 == 0 ) { + out << "[" << DUMP_HEX0x_FORMAT( 8 ) << i << "]"; + } + + out << " " << DUMP_HEX0x_FORMAT( 2 ) + << ( pdata[i] & 0x000000FF ); + + if ( i % 16 == 15 ) { + out << std::endl; + } + } + if ( i % 16 != 0 ) { + out << std::endl; + } + + out.flags( original_flags ); + } + + return; + } + + //------------------------------------------------------------------------------ + static void segment_datas( std::ostream& out, const elfio& reader ) + { + Elf_Half n = reader.segments.size(); + + if ( n == 0 ) { + return; + } + + out << "Segment Data:" << std::endl; + + for ( Elf_Half i = 0; i < n; ++i ) { // For all sections + segment* seg = reader.segments[i]; + segment_data( out, i, seg ); + } + + out << std::endl; + } + +//------------------------------------------------------------------------------ +#define STR_FUNC_TABLE( name ) \ + template static std::string str_##name( const T key ) \ + { \ + return format_assoc( name##_table, key ); \ + } + + STR_FUNC_TABLE( class ) + STR_FUNC_TABLE( endian ) + STR_FUNC_TABLE( version ) + STR_FUNC_TABLE( type ) + STR_FUNC_TABLE( machine ) + STR_FUNC_TABLE( section_type ) + STR_FUNC_TABLE( segment_type ) + STR_FUNC_TABLE( segment_flag ) + STR_FUNC_TABLE( symbol_bind ) + STR_FUNC_TABLE( symbol_type ) + STR_FUNC_TABLE( dynamic_tag ) + +#undef STR_FUNC_TABLE + + private: + //------------------------------------------------------------------------------ + template + std::string static find_value_in_table( const T& table, const K& key ) + { + std::string res = "?"; + for ( unsigned int i = 0; i < sizeof( table ) / sizeof( table[0] ); + ++i ) { + if ( table[i].key == key ) { + res = table[i].str; + break; + } + } + + return res; + } + + //------------------------------------------------------------------------------ + template + static std::string format_assoc( const T& table, const K& key ) + { + std::string str = find_value_in_table( table, key ); + if ( str == "?" ) { + std::ostringstream oss; + oss << str << " (0x" << std::hex << key << ")"; + str = oss.str(); + } + + return str; + } + + //------------------------------------------------------------------------------ + template + static std::string format_assoc( const T& table, const char key ) + { + return format_assoc( table, (const int)key ); + } + + //------------------------------------------------------------------------------ + static std::string section_flags( Elf_Xword flags ) + { + std::string ret = ""; + if ( flags & SHF_WRITE ) { + ret += "W"; + } + if ( flags & SHF_ALLOC ) { + ret += "A"; + } + if ( flags & SHF_EXECINSTR ) { + ret += "X"; + } + + return ret; + } + +#undef DUMP_DEC_FORMAT +#undef DUMP_HEX0x_FORMAT +#undef DUMP_STR_FORMAT +}; // class dump +} // namespace ELFIO + +#endif // ELFIO_DUMP_HPP diff --git a/tools/elfio/elfio_dynamic.hpp b/tools/elfio/elfio_dynamic.hpp new file mode 100644 index 00000000000..0bbc6f0c732 --- /dev/null +++ b/tools/elfio/elfio_dynamic.hpp @@ -0,0 +1,261 @@ +/* +Copyright (C) 2001-present by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELFIO_DYNAMIC_HPP +#define ELFIO_DYNAMIC_HPP + +#include + +namespace ELFIO { + +//------------------------------------------------------------------------------ +template class dynamic_section_accessor_template +{ + public: + //------------------------------------------------------------------------------ + dynamic_section_accessor_template( const elfio& elf_file, S* section ) + : elf_file( elf_file ), dynamic_section( section ), entries_num( 0 ) + { + } + + //------------------------------------------------------------------------------ + Elf_Xword get_entries_num() const + { + if ( ( 0 == entries_num ) && + ( 0 != dynamic_section->get_entry_size() ) ) { + entries_num = + dynamic_section->get_size() / dynamic_section->get_entry_size(); + Elf_Xword i; + Elf_Xword tag; + Elf_Xword value; + std::string str; + for ( i = 0; i < entries_num; i++ ) { + get_entry( i, tag, value, str ); + if ( tag == DT_NULL ) + break; + } + entries_num = std::min( entries_num, i + 1 ); + } + + return entries_num; + } + + //------------------------------------------------------------------------------ + bool get_entry( Elf_Xword index, + Elf_Xword& tag, + Elf_Xword& value, + std::string& str ) const + { + if ( index >= get_entries_num() ) { // Is index valid + return false; + } + + if ( elf_file.get_class() == ELFCLASS32 ) { + generic_get_entry_dyn( index, tag, value ); + } + else { + generic_get_entry_dyn( index, tag, value ); + } + + // If the tag may have a string table reference, prepare the string + if ( tag == DT_NEEDED || tag == DT_SONAME || tag == DT_RPATH || + tag == DT_RUNPATH ) { + string_section_accessor strsec( + elf_file.sections[get_string_table_index()] ); + const char* result = strsec.get_string( value ); + if ( nullptr == result ) { + str.clear(); + return false; + } + str = result; + } + else { + str.clear(); + } + + return true; + } + + //------------------------------------------------------------------------------ + void add_entry( Elf_Xword tag, Elf_Xword value ) + { + if ( elf_file.get_class() == ELFCLASS32 ) { + generic_add_entry_dyn( tag, value ); + } + else { + generic_add_entry_dyn( tag, value ); + } + } + + //------------------------------------------------------------------------------ + void add_entry( Elf_Xword tag, const std::string& str ) + { + string_section_accessor strsec( + elf_file.sections[get_string_table_index()] ); + Elf_Xword value = strsec.add_string( str ); + add_entry( tag, value ); + } + + //------------------------------------------------------------------------------ + private: + //------------------------------------------------------------------------------ + Elf_Half get_string_table_index() const + { + return (Elf_Half)dynamic_section->get_link(); + } + + //------------------------------------------------------------------------------ + template + void generic_get_entry_dyn( Elf_Xword index, + Elf_Xword& tag, + Elf_Xword& value ) const + { + const endianess_convertor& convertor = elf_file.get_convertor(); + + // Check unusual case when dynamic section has no data + if ( dynamic_section->get_data() == nullptr || + ( index + 1 ) * dynamic_section->get_entry_size() > + dynamic_section->get_size() ) { + tag = DT_NULL; + value = 0; + return; + } + + const T* pEntry = reinterpret_cast( + dynamic_section->get_data() + + index * dynamic_section->get_entry_size() ); + tag = convertor( pEntry->d_tag ); + switch ( tag ) { + case DT_NULL: + case DT_SYMBOLIC: + case DT_TEXTREL: + case DT_BIND_NOW: + value = 0; + break; + case DT_NEEDED: + case DT_PLTRELSZ: + case DT_RELASZ: + case DT_RELAENT: + case DT_STRSZ: + case DT_SYMENT: + case DT_SONAME: + case DT_RPATH: + case DT_RELSZ: + case DT_RELENT: + case DT_PLTREL: + case DT_INIT_ARRAYSZ: + case DT_FINI_ARRAYSZ: + case DT_RUNPATH: + case DT_FLAGS: + case DT_PREINIT_ARRAYSZ: + value = convertor( pEntry->d_un.d_val ); + break; + case DT_PLTGOT: + case DT_HASH: + case DT_STRTAB: + case DT_SYMTAB: + case DT_RELA: + case DT_INIT: + case DT_FINI: + case DT_REL: + case DT_DEBUG: + case DT_JMPREL: + case DT_INIT_ARRAY: + case DT_FINI_ARRAY: + case DT_PREINIT_ARRAY: + default: + value = convertor( pEntry->d_un.d_ptr ); + break; + } + } + + //------------------------------------------------------------------------------ + template + void generic_add_entry_dyn( Elf_Xword tag, Elf_Xword value ) + { + const endianess_convertor& convertor = elf_file.get_convertor(); + + T entry; + + switch ( tag ) { + case DT_NULL: + case DT_SYMBOLIC: + case DT_TEXTREL: + case DT_BIND_NOW: + entry.d_un.d_val = convertor( 0 ); + break; + case DT_NEEDED: + case DT_PLTRELSZ: + case DT_RELASZ: + case DT_RELAENT: + case DT_STRSZ: + case DT_SYMENT: + case DT_SONAME: + case DT_RPATH: + case DT_RELSZ: + case DT_RELENT: + case DT_PLTREL: + case DT_INIT_ARRAYSZ: + case DT_FINI_ARRAYSZ: + case DT_RUNPATH: + case DT_FLAGS: + case DT_PREINIT_ARRAYSZ: + entry.d_un.d_val = convertor( value ); + break; + case DT_PLTGOT: + case DT_HASH: + case DT_STRTAB: + case DT_SYMTAB: + case DT_RELA: + case DT_INIT: + case DT_FINI: + case DT_REL: + case DT_DEBUG: + case DT_JMPREL: + case DT_INIT_ARRAY: + case DT_FINI_ARRAY: + case DT_PREINIT_ARRAY: + default: + entry.d_un.d_ptr = convertor( value ); + break; + } + + entry.d_tag = convertor( tag ); + + dynamic_section->append_data( reinterpret_cast( &entry ), + sizeof( entry ) ); + } + + //------------------------------------------------------------------------------ + private: + const elfio& elf_file; + S* dynamic_section; + mutable Elf_Xword entries_num; +}; + +using dynamic_section_accessor = dynamic_section_accessor_template
; +using const_dynamic_section_accessor = + dynamic_section_accessor_template; + +} // namespace ELFIO + +#endif // ELFIO_DYNAMIC_HPP diff --git a/tools/elfio/elfio_header.hpp b/tools/elfio/elfio_header.hpp new file mode 100644 index 00000000000..1c9a437458c --- /dev/null +++ b/tools/elfio/elfio_header.hpp @@ -0,0 +1,158 @@ +/* +Copyright (C) 2001-present by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELF_HEADER_HPP +#define ELF_HEADER_HPP + +#include + +namespace ELFIO { + +class elf_header +{ + public: + virtual ~elf_header() = default; + + virtual bool load( std::istream& stream ) = 0; + virtual bool save( std::ostream& stream ) const = 0; + + // ELF header functions + ELFIO_GET_ACCESS_DECL( unsigned char, class ); + ELFIO_GET_ACCESS_DECL( unsigned char, elf_version ); + ELFIO_GET_ACCESS_DECL( unsigned char, encoding ); + ELFIO_GET_ACCESS_DECL( Elf_Half, header_size ); + ELFIO_GET_ACCESS_DECL( Elf_Half, section_entry_size ); + ELFIO_GET_ACCESS_DECL( Elf_Half, segment_entry_size ); + + ELFIO_GET_SET_ACCESS_DECL( Elf_Word, version ); + ELFIO_GET_SET_ACCESS_DECL( unsigned char, os_abi ); + ELFIO_GET_SET_ACCESS_DECL( unsigned char, abi_version ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Half, type ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Half, machine ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Word, flags ); + ELFIO_GET_SET_ACCESS_DECL( Elf64_Addr, entry ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Half, sections_num ); + ELFIO_GET_SET_ACCESS_DECL( Elf64_Off, sections_offset ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Half, segments_num ); + ELFIO_GET_SET_ACCESS_DECL( Elf64_Off, segments_offset ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Half, section_name_str_index ); +}; + +template struct elf_header_impl_types; +template <> struct elf_header_impl_types +{ + using Phdr_type = Elf32_Phdr; + using Shdr_type = Elf32_Shdr; + static const unsigned char file_class = ELFCLASS32; +}; +template <> struct elf_header_impl_types +{ + using Phdr_type = Elf64_Phdr; + using Shdr_type = Elf64_Shdr; + static const unsigned char file_class = ELFCLASS64; +}; + +template class elf_header_impl : public elf_header +{ + public: + //------------------------------------------------------------------------------ + elf_header_impl( endianess_convertor* convertor, + unsigned char encoding, + const address_translator* translator ) + { + this->convertor = convertor; + this->translator = translator; + + std::fill_n( reinterpret_cast( &header ), sizeof( header ), + '\0' ); + + header.e_ident[EI_MAG0] = ELFMAG0; + header.e_ident[EI_MAG1] = ELFMAG1; + header.e_ident[EI_MAG2] = ELFMAG2; + header.e_ident[EI_MAG3] = ELFMAG3; + header.e_ident[EI_CLASS] = elf_header_impl_types::file_class; + header.e_ident[EI_DATA] = encoding; + header.e_ident[EI_VERSION] = EV_CURRENT; + header.e_version = ( *convertor )( (Elf_Word)EV_CURRENT ); + header.e_ehsize = ( sizeof( header ) ); + header.e_ehsize = ( *convertor )( header.e_ehsize ); + header.e_shstrndx = ( *convertor )( (Elf_Half)1 ); + header.e_phentsize = + sizeof( typename elf_header_impl_types::Phdr_type ); + header.e_shentsize = + sizeof( typename elf_header_impl_types::Shdr_type ); + header.e_phentsize = ( *convertor )( header.e_phentsize ); + header.e_shentsize = ( *convertor )( header.e_shentsize ); + } + + //------------------------------------------------------------------------------ + bool load( std::istream& stream ) override + { + stream.seekg( ( *translator )[0] ); + stream.read( reinterpret_cast( &header ), sizeof( header ) ); + + return ( stream.gcount() == sizeof( header ) ); + } + + //------------------------------------------------------------------------------ + bool save( std::ostream& stream ) const override + { + stream.seekp( ( *translator )[0] ); + stream.write( reinterpret_cast( &header ), + sizeof( header ) ); + + return stream.good(); + } + + //------------------------------------------------------------------------------ + // ELF header functions + ELFIO_GET_ACCESS( unsigned char, class, header.e_ident[EI_CLASS] ); + ELFIO_GET_ACCESS( unsigned char, elf_version, header.e_ident[EI_VERSION] ); + ELFIO_GET_ACCESS( unsigned char, encoding, header.e_ident[EI_DATA] ); + ELFIO_GET_ACCESS( Elf_Half, header_size, header.e_ehsize ); + ELFIO_GET_ACCESS( Elf_Half, section_entry_size, header.e_shentsize ); + ELFIO_GET_ACCESS( Elf_Half, segment_entry_size, header.e_phentsize ); + + ELFIO_GET_SET_ACCESS( Elf_Word, version, header.e_version ); + ELFIO_GET_SET_ACCESS( unsigned char, os_abi, header.e_ident[EI_OSABI] ); + ELFIO_GET_SET_ACCESS( unsigned char, + abi_version, + header.e_ident[EI_ABIVERSION] ); + ELFIO_GET_SET_ACCESS( Elf_Half, type, header.e_type ); + ELFIO_GET_SET_ACCESS( Elf_Half, machine, header.e_machine ); + ELFIO_GET_SET_ACCESS( Elf_Word, flags, header.e_flags ); + ELFIO_GET_SET_ACCESS( Elf_Half, section_name_str_index, header.e_shstrndx ); + ELFIO_GET_SET_ACCESS( Elf64_Addr, entry, header.e_entry ); + ELFIO_GET_SET_ACCESS( Elf_Half, sections_num, header.e_shnum ); + ELFIO_GET_SET_ACCESS( Elf64_Off, sections_offset, header.e_shoff ); + ELFIO_GET_SET_ACCESS( Elf_Half, segments_num, header.e_phnum ); + ELFIO_GET_SET_ACCESS( Elf64_Off, segments_offset, header.e_phoff ); + + private: + T header; + endianess_convertor* convertor; + const address_translator* translator; +}; + +} // namespace ELFIO + +#endif // ELF_HEADER_HPP diff --git a/tools/elfio/elfio_modinfo.hpp b/tools/elfio/elfio_modinfo.hpp new file mode 100644 index 00000000000..c21d5d44ee3 --- /dev/null +++ b/tools/elfio/elfio_modinfo.hpp @@ -0,0 +1,122 @@ +/* +Copyright (C) 2001-present by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELFIO_MODINFO_HPP +#define ELFIO_MODINFO_HPP + +#include +#include + +namespace ELFIO { + +//------------------------------------------------------------------------------ +template class modinfo_section_accessor_template +{ + public: + //------------------------------------------------------------------------------ + modinfo_section_accessor_template( S* section ) : modinfo_section( section ) + { + process_section(); + } + + //------------------------------------------------------------------------------ + Elf_Word get_attribute_num() const { return (Elf_Word)content.size(); } + + //------------------------------------------------------------------------------ + bool + get_attribute( Elf_Word no, std::string& field, std::string& value ) const + { + if ( no < content.size() ) { + field = content[no].first; + value = content[no].second; + return true; + } + + return false; + } + + //------------------------------------------------------------------------------ + bool get_attribute( const std::string field_name, std::string& value ) const + { + for ( auto i : content ) { + if ( field_name == i.first ) { + value = i.second; + return true; + } + } + + return false; + } + + //------------------------------------------------------------------------------ + Elf_Word add_attribute( const std::string field, const std::string value ) + { + Elf_Word current_position = 0; + + if ( modinfo_section ) { + // Strings are addeded to the end of the current section data + current_position = (Elf_Word)modinfo_section->get_size(); + + std::string attribute = field + "=" + value; + + modinfo_section->append_data( attribute + '\0' ); + content.emplace_back( field, value ); + } + + return current_position; + } + + //------------------------------------------------------------------------------ + private: + void process_section() + { + const char* pdata = modinfo_section->get_data(); + if ( pdata ) { + ELFIO::Elf_Xword i = 0; + while ( i < modinfo_section->get_size() ) { + while ( i < modinfo_section->get_size() && !pdata[i] ) + i++; + if ( i < modinfo_section->get_size() ) { + std::string info = pdata + i; + size_t loc = info.find( '=' ); + content.emplace_back( info.substr( 0, loc ), + info.substr( loc + 1 ) ); + + i += info.length(); + } + } + } + } + + //------------------------------------------------------------------------------ + private: + S* modinfo_section; + std::vector> content; +}; + +using modinfo_section_accessor = modinfo_section_accessor_template
; +using const_modinfo_section_accessor = + modinfo_section_accessor_template; + +} // namespace ELFIO + +#endif // ELFIO_MODINFO_HPP diff --git a/tools/elfio/elfio_note.hpp b/tools/elfio/elfio_note.hpp new file mode 100644 index 00000000000..e8494d9126c --- /dev/null +++ b/tools/elfio/elfio_note.hpp @@ -0,0 +1,177 @@ +/* +Copyright (C) 2001-present by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELFIO_NOTE_HPP +#define ELFIO_NOTE_HPP + +namespace ELFIO { + +//------------------------------------------------------------------------------ +// There are discrepancies in documentations. SCO documentation +// (http://www.sco.com/developers/gabi/latest/ch5.pheader.html#note_section) +// requires 8 byte entries alignment for 64-bit ELF file, +// but Oracle's definition uses the same structure +// for 32-bit and 64-bit formats. +// (https://docs.oracle.com/cd/E23824_01/html/819-0690/chapter6-18048.html) +// +// It looks like EM_X86_64 Linux implementation is similar to Oracle's +// definition. Therefore, the same alignment works for both formats +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +template +class note_section_accessor_template +{ + public: + //------------------------------------------------------------------------------ + note_section_accessor_template( const elfio& elf_file, S* section ) + : elf_file( elf_file ), notes( section ) + { + process_section(); + } + + //------------------------------------------------------------------------------ + Elf_Word get_notes_num() const + { + return (Elf_Word)note_start_positions.size(); + } + + //------------------------------------------------------------------------------ + bool get_note( Elf_Word index, + Elf_Word& type, + std::string& name, + void*& desc, + Elf_Word& descSize ) const + { + if ( index >= ( notes->*F_get_size )() ) { + return false; + } + + const char* pData = notes->get_data() + note_start_positions[index]; + int align = sizeof( Elf_Word ); + + const endianess_convertor& convertor = elf_file.get_convertor(); + type = convertor( *(const Elf_Word*)( pData + 2 * (size_t)align ) ); + Elf_Word namesz = convertor( *(const Elf_Word*)( pData ) ); + descSize = convertor( *(const Elf_Word*)( pData + sizeof( namesz ) ) ); + + Elf_Xword max_name_size = + ( notes->*F_get_size )() - note_start_positions[index]; + if ( namesz < 1 || namesz > max_name_size || + (Elf_Xword)namesz + descSize > max_name_size ) { + return false; + } + name.assign( pData + 3 * (size_t)align, namesz - 1 ); + if ( 0 == descSize ) { + desc = nullptr; + } + else { + desc = const_cast( pData + 3 * (size_t)align + + ( ( namesz + align - 1 ) / align ) * + (size_t)align ); + } + + return true; + } + + //------------------------------------------------------------------------------ + void add_note( Elf_Word type, + const std::string& name, + const void* desc, + Elf_Word descSize ) + { + const endianess_convertor& convertor = elf_file.get_convertor(); + + int align = sizeof( Elf_Word ); + Elf_Word nameLen = (Elf_Word)name.size() + 1; + Elf_Word nameLenConv = convertor( nameLen ); + std::string buffer( reinterpret_cast( &nameLenConv ), align ); + Elf_Word descSizeConv = convertor( descSize ); + + buffer.append( reinterpret_cast( &descSizeConv ), align ); + type = convertor( type ); + buffer.append( reinterpret_cast( &type ), align ); + buffer.append( name ); + buffer.append( 1, '\x00' ); + const char pad[] = { '\0', '\0', '\0', '\0' }; + if ( nameLen % align != 0 ) { + buffer.append( pad, (size_t)align - nameLen % align ); + } + if ( desc != nullptr && descSize != 0 ) { + buffer.append( reinterpret_cast( desc ), descSize ); + if ( descSize % align != 0 ) { + buffer.append( pad, (size_t)align - descSize % align ); + } + } + + note_start_positions.emplace_back( ( notes->*F_get_size )() ); + notes->append_data( buffer ); + } + + private: + //------------------------------------------------------------------------------ + void process_section() + { + const endianess_convertor& convertor = elf_file.get_convertor(); + const char* data = notes->get_data(); + Elf_Xword size = ( notes->*F_get_size )(); + Elf_Xword current = 0; + + note_start_positions.clear(); + + // Is it empty? + if ( nullptr == data || 0 == size ) { + return; + } + + Elf_Word align = sizeof( Elf_Word ); + while ( current + (Elf_Xword)3 * align <= size ) { + note_start_positions.emplace_back( current ); + Elf_Word namesz = convertor( *(const Elf_Word*)( data + current ) ); + Elf_Word descsz = convertor( + *(const Elf_Word*)( data + current + sizeof( namesz ) ) ); + + current += (Elf_Xword)3 * sizeof( Elf_Word ) + + ( ( namesz + align - 1 ) / align ) * (Elf_Xword)align + + ( ( descsz + align - 1 ) / align ) * (Elf_Xword)align; + } + } + + //------------------------------------------------------------------------------ + private: + const elfio& elf_file; + S* notes; + std::vector note_start_positions; +}; + +using note_section_accessor = + note_section_accessor_template; +using const_note_section_accessor = + note_section_accessor_template; +using note_segment_accessor = + note_section_accessor_template; +using const_note_segment_accessor = + note_section_accessor_template; + +} // namespace ELFIO + +#endif // ELFIO_NOTE_HPP diff --git a/tools/elfio/elfio_relocation.hpp b/tools/elfio/elfio_relocation.hpp new file mode 100644 index 00000000000..1a7211475f3 --- /dev/null +++ b/tools/elfio/elfio_relocation.hpp @@ -0,0 +1,459 @@ +/* +Copyright (C) 2001-present by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELFIO_RELOCATION_HPP +#define ELFIO_RELOCATION_HPP + +namespace ELFIO { + +template struct get_sym_and_type; +template <> struct get_sym_and_type +{ + static int get_r_sym( Elf_Xword info ) + { + return ELF32_R_SYM( (Elf_Word)info ); + } + static int get_r_type( Elf_Xword info ) + { + return ELF32_R_TYPE( (Elf_Word)info ); + } +}; +template <> struct get_sym_and_type +{ + static int get_r_sym( Elf_Xword info ) + { + return ELF32_R_SYM( (Elf_Word)info ); + } + static int get_r_type( Elf_Xword info ) + { + return ELF32_R_TYPE( (Elf_Word)info ); + } +}; +template <> struct get_sym_and_type +{ + static int get_r_sym( Elf_Xword info ) { return ELF64_R_SYM( info ); } + static int get_r_type( Elf_Xword info ) { return ELF64_R_TYPE( info ); } +}; +template <> struct get_sym_and_type +{ + static int get_r_sym( Elf_Xword info ) { return ELF64_R_SYM( info ); } + static int get_r_type( Elf_Xword info ) { return ELF64_R_TYPE( info ); } +}; + +//------------------------------------------------------------------------------ +template class relocation_section_accessor_template +{ + public: + //------------------------------------------------------------------------------ + relocation_section_accessor_template( const elfio& elf_file, S* section ) + : elf_file( elf_file ), relocation_section( section ) + { + } + + //------------------------------------------------------------------------------ + Elf_Xword get_entries_num() const + { + Elf_Xword nRet = 0; + + if ( 0 != relocation_section->get_entry_size() ) { + nRet = relocation_section->get_size() / + relocation_section->get_entry_size(); + } + + return nRet; + } + + //------------------------------------------------------------------------------ + bool get_entry( Elf_Xword index, + Elf64_Addr& offset, + Elf_Word& symbol, + unsigned char& type, + Elf_Sxword& addend ) const + { + if ( index >= get_entries_num() ) { // Is index valid + return false; + } + + if ( elf_file.get_class() == ELFCLASS32 ) { + if ( SHT_REL == relocation_section->get_type() ) { + generic_get_entry_rel( index, offset, symbol, type, + addend ); + } + else if ( SHT_RELA == relocation_section->get_type() ) { + generic_get_entry_rela( index, offset, symbol, type, + addend ); + } + } + else { + if ( SHT_REL == relocation_section->get_type() ) { + generic_get_entry_rel( index, offset, symbol, type, + addend ); + } + else if ( SHT_RELA == relocation_section->get_type() ) { + generic_get_entry_rela( index, offset, symbol, type, + addend ); + } + } + + return true; + } + + //------------------------------------------------------------------------------ + bool get_entry( Elf_Xword index, + Elf64_Addr& offset, + Elf64_Addr& symbolValue, + std::string& symbolName, + unsigned char& type, + Elf_Sxword& addend, + Elf_Sxword& calcValue ) const + { + // Do regular job + Elf_Word symbol; + bool ret = get_entry( index, offset, symbol, type, addend ); + + // Find the symbol + Elf_Xword size; + unsigned char bind; + unsigned char symbolType; + Elf_Half section; + unsigned char other; + + symbol_section_accessor symbols( + elf_file, elf_file.sections[get_symbol_table_index()] ); + ret = ret && symbols.get_symbol( symbol, symbolName, symbolValue, size, + bind, symbolType, section, other ); + + if ( ret ) { // Was it successful? + switch ( type ) { + case R_386_NONE: // none + calcValue = 0; + break; + case R_386_32: // S + A + calcValue = symbolValue + addend; + break; + case R_386_PC32: // S + A - P + calcValue = symbolValue + addend - offset; + break; + case R_386_GOT32: // G + A - P + calcValue = 0; + break; + case R_386_PLT32: // L + A - P + calcValue = 0; + break; + case R_386_COPY: // none + calcValue = 0; + break; + case R_386_GLOB_DAT: // S + case R_386_JMP_SLOT: // S + calcValue = symbolValue; + break; + case R_386_RELATIVE: // B + A + calcValue = addend; + break; + case R_386_GOTOFF: // S + A - GOT + calcValue = 0; + break; + case R_386_GOTPC: // GOT + A - P + calcValue = 0; + break; + default: // Not recognized symbol! + calcValue = 0; + break; + } + } + + return ret; + } + + //------------------------------------------------------------------------------ + bool set_entry( Elf_Xword index, + Elf64_Addr offset, + Elf_Word symbol, + unsigned char type, + Elf_Sxword addend ) + { + if ( index >= get_entries_num() ) { // Is index valid + return false; + } + + if ( elf_file.get_class() == ELFCLASS32 ) { + if ( SHT_REL == relocation_section->get_type() ) { + generic_set_entry_rel( index, offset, symbol, type, + addend ); + } + else if ( SHT_RELA == relocation_section->get_type() ) { + generic_set_entry_rela( index, offset, symbol, type, + addend ); + } + } + else { + if ( SHT_REL == relocation_section->get_type() ) { + generic_set_entry_rel( index, offset, symbol, type, + addend ); + } + else if ( SHT_RELA == relocation_section->get_type() ) { + generic_set_entry_rela( index, offset, symbol, type, + addend ); + } + } + + return true; + } + + //------------------------------------------------------------------------------ + void add_entry( Elf64_Addr offset, Elf_Xword info ) + { + if ( elf_file.get_class() == ELFCLASS32 ) { + generic_add_entry( offset, info ); + } + else { + generic_add_entry( offset, info ); + } + } + + //------------------------------------------------------------------------------ + void add_entry( Elf64_Addr offset, Elf_Word symbol, unsigned char type ) + { + Elf_Xword info; + if ( elf_file.get_class() == ELFCLASS32 ) { + info = ELF32_R_INFO( (Elf_Xword)symbol, type ); + } + else { + info = ELF64_R_INFO( (Elf_Xword)symbol, type ); + } + + add_entry( offset, info ); + } + + //------------------------------------------------------------------------------ + void add_entry( Elf64_Addr offset, Elf_Xword info, Elf_Sxword addend ) + { + if ( elf_file.get_class() == ELFCLASS32 ) { + generic_add_entry( offset, info, addend ); + } + else { + generic_add_entry( offset, info, addend ); + } + } + + //------------------------------------------------------------------------------ + void add_entry( Elf64_Addr offset, + Elf_Word symbol, + unsigned char type, + Elf_Sxword addend ) + { + Elf_Xword info; + if ( elf_file.get_class() == ELFCLASS32 ) { + info = ELF32_R_INFO( (Elf_Xword)symbol, type ); + } + else { + info = ELF64_R_INFO( (Elf_Xword)symbol, type ); + } + + add_entry( offset, info, addend ); + } + + //------------------------------------------------------------------------------ + void add_entry( string_section_accessor str_writer, + const char* str, + symbol_section_accessor sym_writer, + Elf64_Addr value, + Elf_Word size, + unsigned char sym_info, + unsigned char other, + Elf_Half shndx, + Elf64_Addr offset, + unsigned char type ) + { + Elf_Word str_index = str_writer.add_string( str ); + Elf_Word sym_index = sym_writer.add_symbol( str_index, value, size, + sym_info, other, shndx ); + add_entry( offset, sym_index, type ); + } + + //------------------------------------------------------------------------------ + void swap_symbols( Elf_Xword first, Elf_Xword second ) + { + Elf64_Addr offset; + Elf_Word symbol; + unsigned char rtype; + Elf_Sxword addend; + for ( Elf_Word i = 0; i < get_entries_num(); i++ ) { + get_entry( i, offset, symbol, rtype, addend ); + if ( symbol == first ) { + set_entry( i, offset, (Elf_Word)second, rtype, addend ); + } + if ( symbol == second ) { + set_entry( i, offset, (Elf_Word)first, rtype, addend ); + } + } + } + + //------------------------------------------------------------------------------ + private: + //------------------------------------------------------------------------------ + Elf_Half get_symbol_table_index() const + { + return (Elf_Half)relocation_section->get_link(); + } + + //------------------------------------------------------------------------------ + template + void generic_get_entry_rel( Elf_Xword index, + Elf64_Addr& offset, + Elf_Word& symbol, + unsigned char& type, + Elf_Sxword& addend ) const + { + const endianess_convertor& convertor = elf_file.get_convertor(); + + const T* pEntry = reinterpret_cast( + relocation_section->get_data() + + index * relocation_section->get_entry_size() ); + offset = convertor( pEntry->r_offset ); + Elf_Xword tmp = convertor( pEntry->r_info ); + symbol = get_sym_and_type::get_r_sym( tmp ); + type = get_sym_and_type::get_r_type( tmp ); + addend = 0; + } + + //------------------------------------------------------------------------------ + template + void generic_get_entry_rela( Elf_Xword index, + Elf64_Addr& offset, + Elf_Word& symbol, + unsigned char& type, + Elf_Sxword& addend ) const + { + const endianess_convertor& convertor = elf_file.get_convertor(); + + const T* pEntry = reinterpret_cast( + relocation_section->get_data() + + index * relocation_section->get_entry_size() ); + offset = convertor( pEntry->r_offset ); + Elf_Xword tmp = convertor( pEntry->r_info ); + symbol = get_sym_and_type::get_r_sym( tmp ); + type = get_sym_and_type::get_r_type( tmp ); + addend = convertor( pEntry->r_addend ); + } + + //------------------------------------------------------------------------------ + template + void generic_set_entry_rel( Elf_Xword index, + Elf64_Addr offset, + Elf_Word symbol, + unsigned char type, + Elf_Sxword ) + { + const endianess_convertor& convertor = elf_file.get_convertor(); + + T* pEntry = const_cast( reinterpret_cast( + relocation_section->get_data() + + index * relocation_section->get_entry_size() ) ); + + if ( elf_file.get_class() == ELFCLASS32 ) { + pEntry->r_info = ELF32_R_INFO( (Elf_Xword)symbol, type ); + } + else { + pEntry->r_info = ELF64_R_INFO( (Elf_Xword)symbol, type ); + } + pEntry->r_offset = offset; + pEntry->r_offset = convertor( pEntry->r_offset ); + pEntry->r_info = convertor( pEntry->r_info ); + } + + //------------------------------------------------------------------------------ + template + void generic_set_entry_rela( Elf_Xword index, + Elf64_Addr offset, + Elf_Word symbol, + unsigned char type, + Elf_Sxword addend ) + { + const endianess_convertor& convertor = elf_file.get_convertor(); + + T* pEntry = const_cast( reinterpret_cast( + relocation_section->get_data() + + index * relocation_section->get_entry_size() ) ); + + if ( elf_file.get_class() == ELFCLASS32 ) { + pEntry->r_info = ELF32_R_INFO( (Elf_Xword)symbol, type ); + } + else { + pEntry->r_info = ELF64_R_INFO( (Elf_Xword)symbol, type ); + } + pEntry->r_offset = offset; + pEntry->r_addend = addend; + pEntry->r_offset = convertor( pEntry->r_offset ); + pEntry->r_info = convertor( pEntry->r_info ); + pEntry->r_addend = convertor( pEntry->r_addend ); + } + + //------------------------------------------------------------------------------ + template + void generic_add_entry( Elf64_Addr offset, Elf_Xword info ) + { + const endianess_convertor& convertor = elf_file.get_convertor(); + + T entry; + entry.r_offset = offset; + entry.r_info = info; + entry.r_offset = convertor( entry.r_offset ); + entry.r_info = convertor( entry.r_info ); + + relocation_section->append_data( reinterpret_cast( &entry ), + sizeof( entry ) ); + } + + //------------------------------------------------------------------------------ + template + void + generic_add_entry( Elf64_Addr offset, Elf_Xword info, Elf_Sxword addend ) + { + const endianess_convertor& convertor = elf_file.get_convertor(); + + T entry; + entry.r_offset = offset; + entry.r_info = info; + entry.r_addend = addend; + entry.r_offset = convertor( entry.r_offset ); + entry.r_info = convertor( entry.r_info ); + entry.r_addend = convertor( entry.r_addend ); + + relocation_section->append_data( reinterpret_cast( &entry ), + sizeof( entry ) ); + } + + //------------------------------------------------------------------------------ + private: + const elfio& elf_file; + S* relocation_section; +}; + +using relocation_section_accessor = + relocation_section_accessor_template
; +using const_relocation_section_accessor = + relocation_section_accessor_template; + +} // namespace ELFIO + +#endif // ELFIO_RELOCATION_HPP diff --git a/tools/elfio/elfio_section.hpp b/tools/elfio/elfio_section.hpp new file mode 100644 index 00000000000..0699ef104d2 --- /dev/null +++ b/tools/elfio/elfio_section.hpp @@ -0,0 +1,287 @@ +/* +Copyright (C) 2001-present by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELFIO_SECTION_HPP +#define ELFIO_SECTION_HPP + +#include +#include +#include +#include + +namespace ELFIO { + +class section +{ + friend class elfio; + + public: + virtual ~section() = default; + + ELFIO_GET_ACCESS_DECL( Elf_Half, index ); + ELFIO_GET_SET_ACCESS_DECL( std::string, name ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Word, type ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, flags ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Word, info ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Word, link ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, addr_align ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, entry_size ); + ELFIO_GET_SET_ACCESS_DECL( Elf64_Addr, address ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, size ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Word, name_string_offset ); + ELFIO_GET_ACCESS_DECL( Elf64_Off, offset ); + + virtual const char* get_data() const = 0; + virtual void set_data( const char* pData, Elf_Word size ) = 0; + virtual void set_data( const std::string& data ) = 0; + virtual void append_data( const char* pData, Elf_Word size ) = 0; + virtual void append_data( const std::string& data ) = 0; + virtual size_t get_stream_size() const = 0; + virtual void set_stream_size( size_t value ) = 0; + + protected: + ELFIO_SET_ACCESS_DECL( Elf64_Off, offset ); + ELFIO_SET_ACCESS_DECL( Elf_Half, index ); + + virtual void load( std::istream& stream, std::streampos header_offset ) = 0; + virtual void save( std::ostream& stream, + std::streampos header_offset, + std::streampos data_offset ) = 0; + virtual bool is_address_initialized() const = 0; +}; + +template class section_impl : public section +{ + public: + //------------------------------------------------------------------------------ + section_impl( const endianess_convertor* convertor, + const address_translator* translator ) + : convertor( convertor ), translator( translator ) + { + std::fill_n( reinterpret_cast( &header ), sizeof( header ), + '\0' ); + is_address_set = false; + data = nullptr; + data_size = 0; + index = 0; + stream_size = 0; + } + + //------------------------------------------------------------------------------ + ~section_impl() override { delete[] data; } + + //------------------------------------------------------------------------------ + // Section info functions + ELFIO_GET_SET_ACCESS( Elf_Word, type, header.sh_type ); + ELFIO_GET_SET_ACCESS( Elf_Xword, flags, header.sh_flags ); + ELFIO_GET_SET_ACCESS( Elf_Xword, size, header.sh_size ); + ELFIO_GET_SET_ACCESS( Elf_Word, link, header.sh_link ); + ELFIO_GET_SET_ACCESS( Elf_Word, info, header.sh_info ); + ELFIO_GET_SET_ACCESS( Elf_Xword, addr_align, header.sh_addralign ); + ELFIO_GET_SET_ACCESS( Elf_Xword, entry_size, header.sh_entsize ); + ELFIO_GET_SET_ACCESS( Elf_Word, name_string_offset, header.sh_name ); + ELFIO_GET_ACCESS( Elf64_Addr, address, header.sh_addr ); + + //------------------------------------------------------------------------------ + Elf_Half get_index() const override { return index; } + + //------------------------------------------------------------------------------ + std::string get_name() const override { return name; } + + //------------------------------------------------------------------------------ + void set_name( std::string name ) override { this->name = name; } + + //------------------------------------------------------------------------------ + void set_address( Elf64_Addr value ) override + { + header.sh_addr = value; + header.sh_addr = ( *convertor )( header.sh_addr ); + is_address_set = true; + } + + //------------------------------------------------------------------------------ + bool is_address_initialized() const override { return is_address_set; } + + //------------------------------------------------------------------------------ + const char* get_data() const override { return data; } + + //------------------------------------------------------------------------------ + void set_data( const char* raw_data, Elf_Word size ) override + { + if ( get_type() != SHT_NOBITS ) { + delete[] data; + data = new ( std::nothrow ) char[size]; + if ( nullptr != data && nullptr != raw_data ) { + data_size = size; + std::copy( raw_data, raw_data + size, data ); + } + else { + data_size = 0; + } + } + + set_size( data_size ); + if ( translator->empty() ) { + set_stream_size( data_size ); + } + } + + //------------------------------------------------------------------------------ + void set_data( const std::string& str_data ) override + { + return set_data( str_data.c_str(), (Elf_Word)str_data.size() ); + } + + //------------------------------------------------------------------------------ + void append_data( const char* raw_data, Elf_Word size ) override + { + if ( get_type() != SHT_NOBITS ) { + if ( get_size() + size < data_size ) { + std::copy( raw_data, raw_data + size, data + get_size() ); + } + else { + data_size = 2 * ( data_size + size ); + char* new_data = new ( std::nothrow ) char[data_size]; + + if ( nullptr != new_data ) { + std::copy( data, data + get_size(), new_data ); + std::copy( raw_data, raw_data + size, + new_data + get_size() ); + delete[] data; + data = new_data; + } + else { + size = 0; + } + } + set_size( get_size() + size ); + if ( translator->empty() ) { + set_stream_size( get_stream_size() + size ); + } + } + } + + //------------------------------------------------------------------------------ + void append_data( const std::string& str_data ) override + { + return append_data( str_data.c_str(), (Elf_Word)str_data.size() ); + } + + //------------------------------------------------------------------------------ + size_t get_stream_size() const override { return stream_size; } + + //------------------------------------------------------------------------------ + void set_stream_size( size_t value ) override { stream_size = value; } + + //------------------------------------------------------------------------------ + protected: + //------------------------------------------------------------------------------ + ELFIO_GET_SET_ACCESS( Elf64_Off, offset, header.sh_offset ); + + //------------------------------------------------------------------------------ + void set_index( Elf_Half value ) override { index = value; } + + //------------------------------------------------------------------------------ + void load( std::istream& stream, std::streampos header_offset ) override + { + std::fill_n( reinterpret_cast( &header ), sizeof( header ), + '\0' ); + + if ( translator->empty() ) { + stream.seekg( 0, stream.end ); + set_stream_size( stream.tellg() ); + } + else { + set_stream_size( std::numeric_limits::max() ); + } + + stream.seekg( ( *translator )[header_offset] ); + stream.read( reinterpret_cast( &header ), sizeof( header ) ); + + Elf_Xword size = get_size(); + if ( nullptr == data && SHT_NULL != get_type() && + SHT_NOBITS != get_type() && size < get_stream_size() ) { + data = new ( std::nothrow ) char[size + 1]; + + if ( ( 0 != size ) && ( nullptr != data ) ) { + stream.seekg( + ( *translator )[( *convertor )( header.sh_offset )] ); + stream.read( data, size ); + data[size] = 0; // Ensure data is ended with 0 to avoid oob read + data_size = size; + } + else { + data_size = 0; + } + } + } + + //------------------------------------------------------------------------------ + void save( std::ostream& stream, + std::streampos header_offset, + std::streampos data_offset ) override + { + if ( 0 != get_index() ) { + header.sh_offset = data_offset; + header.sh_offset = ( *convertor )( header.sh_offset ); + } + + save_header( stream, header_offset ); + if ( get_type() != SHT_NOBITS && get_type() != SHT_NULL && + get_size() != 0 && data != nullptr ) { + save_data( stream, data_offset ); + } + } + + //------------------------------------------------------------------------------ + private: + //------------------------------------------------------------------------------ + void save_header( std::ostream& stream, std::streampos header_offset ) const + { + adjust_stream_size( stream, header_offset ); + stream.write( reinterpret_cast( &header ), + sizeof( header ) ); + } + + //------------------------------------------------------------------------------ + void save_data( std::ostream& stream, std::streampos data_offset ) const + { + adjust_stream_size( stream, data_offset ); + stream.write( get_data(), get_size() ); + } + + //------------------------------------------------------------------------------ + private: + T header; + Elf_Half index; + std::string name; + char* data; + Elf_Word data_size; + const endianess_convertor* convertor; + const address_translator* translator; + bool is_address_set; + size_t stream_size; +}; + +} // namespace ELFIO + +#endif // ELFIO_SECTION_HPP diff --git a/tools/elfio/elfio_segment.hpp b/tools/elfio/elfio_segment.hpp new file mode 100644 index 00000000000..42eac63725f --- /dev/null +++ b/tools/elfio/elfio_segment.hpp @@ -0,0 +1,225 @@ +/* +Copyright (C) 2001-present by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELFIO_SEGMENT_HPP +#define ELFIO_SEGMENT_HPP + +#include +#include +#include +#include + +namespace ELFIO { + +class segment +{ + friend class elfio; + + public: + virtual ~segment() = default; + + ELFIO_GET_ACCESS_DECL( Elf_Half, index ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Word, type ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Word, flags ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, align ); + ELFIO_GET_SET_ACCESS_DECL( Elf64_Addr, virtual_address ); + ELFIO_GET_SET_ACCESS_DECL( Elf64_Addr, physical_address ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, file_size ); + ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, memory_size ); + ELFIO_GET_ACCESS_DECL( Elf64_Off, offset ); + + virtual const char* get_data() const = 0; + + virtual Elf_Half add_section( section* psec, Elf_Xword addr_align ) = 0; + virtual Elf_Half add_section_index( Elf_Half index, + Elf_Xword addr_align ) = 0; + virtual Elf_Half get_sections_num() const = 0; + virtual Elf_Half get_section_index_at( Elf_Half num ) const = 0; + virtual bool is_offset_initialized() const = 0; + + protected: + ELFIO_SET_ACCESS_DECL( Elf64_Off, offset ); + ELFIO_SET_ACCESS_DECL( Elf_Half, index ); + + virtual const std::vector& get_sections() const = 0; + virtual void load( std::istream& stream, std::streampos header_offset ) = 0; + virtual void save( std::ostream& stream, + std::streampos header_offset, + std::streampos data_offset ) = 0; +}; + +//------------------------------------------------------------------------------ +template class segment_impl : public segment +{ + public: + //------------------------------------------------------------------------------ + segment_impl( const endianess_convertor* convertor, + const address_translator* translator ) + : index( 0 ), data( nullptr ), convertor( convertor ), + translator( translator ), stream_size( 0 ), is_offset_set( false ) + { + std::fill_n( reinterpret_cast( &ph ), sizeof( ph ), '\0' ); + } + + //------------------------------------------------------------------------------ + ~segment_impl() override { delete[] data; } + + //------------------------------------------------------------------------------ + // Section info functions + ELFIO_GET_SET_ACCESS( Elf_Word, type, ph.p_type ); + ELFIO_GET_SET_ACCESS( Elf_Word, flags, ph.p_flags ); + ELFIO_GET_SET_ACCESS( Elf_Xword, align, ph.p_align ); + ELFIO_GET_SET_ACCESS( Elf64_Addr, virtual_address, ph.p_vaddr ); + ELFIO_GET_SET_ACCESS( Elf64_Addr, physical_address, ph.p_paddr ); + ELFIO_GET_SET_ACCESS( Elf_Xword, file_size, ph.p_filesz ); + ELFIO_GET_SET_ACCESS( Elf_Xword, memory_size, ph.p_memsz ); + ELFIO_GET_ACCESS( Elf64_Off, offset, ph.p_offset ); + + //------------------------------------------------------------------------------ + Elf_Half get_index() const override { return index; } + + //------------------------------------------------------------------------------ + const char* get_data() const override { return data; } + + //------------------------------------------------------------------------------ + Elf_Half add_section_index( Elf_Half sec_index, + Elf_Xword addr_align ) override + { + sections.emplace_back( sec_index ); + if ( addr_align > get_align() ) { + set_align( addr_align ); + } + + return (Elf_Half)sections.size(); + } + + //------------------------------------------------------------------------------ + Elf_Half add_section( section* psec, Elf_Xword addr_align ) override + { + return add_section_index( psec->get_index(), addr_align ); + } + + //------------------------------------------------------------------------------ + Elf_Half get_sections_num() const override + { + return (Elf_Half)sections.size(); + } + + //------------------------------------------------------------------------------ + Elf_Half get_section_index_at( Elf_Half num ) const override + { + if ( num < sections.size() ) { + return sections[num]; + } + + return Elf_Half( -1 ); + } + + //------------------------------------------------------------------------------ + protected: + //------------------------------------------------------------------------------ + + //------------------------------------------------------------------------------ + void set_offset( Elf64_Off value ) override + { + ph.p_offset = value; + ph.p_offset = ( *convertor )( ph.p_offset ); + is_offset_set = true; + } + + //------------------------------------------------------------------------------ + bool is_offset_initialized() const override { return is_offset_set; } + + //------------------------------------------------------------------------------ + const std::vector& get_sections() const override + { + return sections; + } + + //------------------------------------------------------------------------------ + void set_index( Elf_Half value ) override { index = value; } + + //------------------------------------------------------------------------------ + void load( std::istream& stream, std::streampos header_offset ) override + { + if ( translator->empty() ) { + stream.seekg( 0, stream.end ); + set_stream_size( stream.tellg() ); + } + else { + set_stream_size( std::numeric_limits::max() ); + } + + stream.seekg( ( *translator )[header_offset] ); + stream.read( reinterpret_cast( &ph ), sizeof( ph ) ); + is_offset_set = true; + + if ( PT_NULL != get_type() && 0 != get_file_size() ) { + stream.seekg( ( *translator )[( *convertor )( ph.p_offset )] ); + Elf_Xword size = get_file_size(); + + if ( size > get_stream_size() ) { + data = nullptr; + } + else { + data = new ( std::nothrow ) char[size + 1]; + + if ( nullptr != data ) { + stream.read( data, size ); + data[size] = 0; + } + } + } + } + + //------------------------------------------------------------------------------ + void save( std::ostream& stream, + std::streampos header_offset, + std::streampos data_offset ) override + { + ph.p_offset = data_offset; + ph.p_offset = ( *convertor )( ph.p_offset ); + adjust_stream_size( stream, header_offset ); + stream.write( reinterpret_cast( &ph ), sizeof( ph ) ); + } + + //------------------------------------------------------------------------------ + size_t get_stream_size() const { return stream_size; } + + //------------------------------------------------------------------------------ + void set_stream_size( size_t value ) { stream_size = value; } + + //------------------------------------------------------------------------------ + private: + T ph; + Elf_Half index; + char* data; + std::vector sections; + const endianess_convertor* convertor; + const address_translator* translator; + size_t stream_size; + bool is_offset_set; +}; + +} // namespace ELFIO + +#endif // ELFIO_SEGMENT_HPP diff --git a/tools/elfio/elfio_strings.hpp b/tools/elfio/elfio_strings.hpp new file mode 100644 index 00000000000..191dab07a00 --- /dev/null +++ b/tools/elfio/elfio_strings.hpp @@ -0,0 +1,96 @@ +/* +Copyright (C) 2001-present by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELFIO_STRINGS_HPP +#define ELFIO_STRINGS_HPP + +#include +#include +#include + +namespace ELFIO { + +//------------------------------------------------------------------------------ +template class string_section_accessor_template +{ + public: + //------------------------------------------------------------------------------ + explicit string_section_accessor_template( S* section ) + : string_section( section ) + { + } + + //------------------------------------------------------------------------------ + const char* get_string( Elf_Word index ) const + { + if ( string_section ) { + if ( index < string_section->get_size() ) { + const char* data = string_section->get_data(); + if ( nullptr != data ) { + return data + index; + } + } + } + + return nullptr; + } + + //------------------------------------------------------------------------------ + Elf_Word add_string( const char* str ) + { + Elf_Word current_position = 0; + + if ( string_section ) { + // Strings are addeded to the end of the current section data + current_position = + static_cast( string_section->get_size() ); + + if ( current_position == 0 ) { + char empty_string = '\0'; + string_section->append_data( &empty_string, 1 ); + current_position++; + } + string_section->append_data( + str, static_cast( std::strlen( str ) + 1 ) ); + } + + return current_position; + } + + //------------------------------------------------------------------------------ + Elf_Word add_string( const std::string& str ) + { + return add_string( str.c_str() ); + } + + //------------------------------------------------------------------------------ + private: + S* string_section; +}; + +using string_section_accessor = string_section_accessor_template
; +using const_string_section_accessor = + string_section_accessor_template; + +} // namespace ELFIO + +#endif // ELFIO_STRINGS_HPP diff --git a/tools/elfio/elfio_symbols.hpp b/tools/elfio/elfio_symbols.hpp new file mode 100644 index 00000000000..33760e4f159 --- /dev/null +++ b/tools/elfio/elfio_symbols.hpp @@ -0,0 +1,549 @@ +/* +Copyright (C) 2001-present by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELFIO_SYMBOLS_HPP +#define ELFIO_SYMBOLS_HPP + +namespace ELFIO { + +//------------------------------------------------------------------------------ +template class symbol_section_accessor_template +{ + public: + //------------------------------------------------------------------------------ + symbol_section_accessor_template( const elfio& elf_file, S* symbol_section ) + : elf_file( elf_file ), symbol_section( symbol_section ) + { + hash_section = nullptr; + hash_section_index = 0; + find_hash_section(); + } + + //------------------------------------------------------------------------------ + Elf_Xword get_symbols_num() const + { + Elf_Xword nRet = 0; + if ( 0 != symbol_section->get_entry_size() && + symbol_section->get_size() <= symbol_section->get_stream_size() ) { + nRet = + symbol_section->get_size() / symbol_section->get_entry_size(); + } + + return nRet; + } + + //------------------------------------------------------------------------------ + bool get_symbol( Elf_Xword index, + std::string& name, + Elf64_Addr& value, + Elf_Xword& size, + unsigned char& bind, + unsigned char& type, + Elf_Half& section_index, + unsigned char& other ) const + { + bool ret = false; + + if ( elf_file.get_class() == ELFCLASS32 ) { + ret = generic_get_symbol( index, name, value, size, bind, + type, section_index, other ); + } + else { + ret = generic_get_symbol( index, name, value, size, bind, + type, section_index, other ); + } + + return ret; + } + + //------------------------------------------------------------------------------ + bool get_symbol( const std::string& name, + Elf64_Addr& value, + Elf_Xword& size, + unsigned char& bind, + unsigned char& type, + Elf_Half& section_index, + unsigned char& other ) const + { + bool ret = false; + + if ( 0 != get_hash_table_index() ) { + if ( hash_section->get_type() == SHT_HASH ) { + ret = hash_lookup( name, value, size, bind, type, section_index, + other ); + } + if ( hash_section->get_type() == SHT_GNU_HASH || + hash_section->get_type() == DT_GNU_HASH ) { + if ( elf_file.get_class() == ELFCLASS32 ) { + ret = gnu_hash_lookup( + name, value, size, bind, type, section_index, other ); + } + else { + ret = gnu_hash_lookup( + name, value, size, bind, type, section_index, other ); + } + } + } + + if ( !ret ) { + for ( Elf_Xword i = 0; !ret && i < get_symbols_num(); i++ ) { + std::string symbol_name; + if ( get_symbol( i, symbol_name, value, size, bind, type, + section_index, other ) ) { + if ( symbol_name == name ) { + ret = true; + } + } + } + } + + return ret; + } + + //------------------------------------------------------------------------------ + bool get_symbol( const Elf64_Addr& value, + std::string& name, + Elf_Xword& size, + unsigned char& bind, + unsigned char& type, + Elf_Half& section_index, + unsigned char& other ) const + { + + const endianess_convertor& convertor = elf_file.get_convertor(); + + Elf_Xword idx = 0; + bool match = false; + Elf64_Addr v = 0; + + if ( elf_file.get_class() == ELFCLASS32 ) { + match = generic_search_symbols( + [&]( const Elf32_Sym* sym ) { + return convertor( sym->st_value ) == value; + }, + idx ); + } + else { + match = generic_search_symbols( + [&]( const Elf64_Sym* sym ) { + return convertor( sym->st_value ) == value; + }, + idx ); + } + + if ( match ) { + return get_symbol( idx, name, v, size, bind, type, section_index, + other ); + } + + return false; + } + + //------------------------------------------------------------------------------ + Elf_Word add_symbol( Elf_Word name, + Elf64_Addr value, + Elf_Xword size, + unsigned char info, + unsigned char other, + Elf_Half shndx ) + { + Elf_Word nRet; + + if ( symbol_section->get_size() == 0 ) { + if ( elf_file.get_class() == ELFCLASS32 ) { + nRet = generic_add_symbol( 0, 0, 0, 0, 0, 0 ); + } + else { + nRet = generic_add_symbol( 0, 0, 0, 0, 0, 0 ); + } + } + + if ( elf_file.get_class() == ELFCLASS32 ) { + nRet = generic_add_symbol( name, value, size, info, + other, shndx ); + } + else { + nRet = generic_add_symbol( name, value, size, info, + other, shndx ); + } + + return nRet; + } + + //------------------------------------------------------------------------------ + Elf_Word add_symbol( Elf_Word name, + Elf64_Addr value, + Elf_Xword size, + unsigned char bind, + unsigned char type, + unsigned char other, + Elf_Half shndx ) + { + return add_symbol( name, value, size, ELF_ST_INFO( bind, type ), other, + shndx ); + } + + //------------------------------------------------------------------------------ + Elf_Word add_symbol( string_section_accessor& pStrWriter, + const char* str, + Elf64_Addr value, + Elf_Xword size, + unsigned char info, + unsigned char other, + Elf_Half shndx ) + { + Elf_Word index = pStrWriter.add_string( str ); + return add_symbol( index, value, size, info, other, shndx ); + } + + //------------------------------------------------------------------------------ + Elf_Word add_symbol( string_section_accessor& pStrWriter, + const char* str, + Elf64_Addr value, + Elf_Xword size, + unsigned char bind, + unsigned char type, + unsigned char other, + Elf_Half shndx ) + { + return add_symbol( pStrWriter, str, value, size, + ELF_ST_INFO( bind, type ), other, shndx ); + } + + //------------------------------------------------------------------------------ + Elf_Xword arrange_local_symbols( + std::function func = + nullptr ) + { + int nRet = 0; + + if ( elf_file.get_class() == ELFCLASS32 ) { + nRet = generic_arrange_local_symbols( func ); + } + else { + nRet = generic_arrange_local_symbols( func ); + } + + return nRet; + } + + //------------------------------------------------------------------------------ + private: + //------------------------------------------------------------------------------ + void find_hash_section() + { + Elf_Half nSecNo = elf_file.sections.size(); + for ( Elf_Half i = 0; i < nSecNo; ++i ) { + const section* sec = elf_file.sections[i]; + if ( sec->get_link() == symbol_section->get_index() && + ( sec->get_type() == SHT_HASH || + sec->get_type() == SHT_GNU_HASH || + sec->get_type() == DT_GNU_HASH ) ) { + hash_section = sec; + hash_section_index = i; + break; + } + } + } + + //------------------------------------------------------------------------------ + Elf_Half get_string_table_index() const + { + return (Elf_Half)symbol_section->get_link(); + } + + //------------------------------------------------------------------------------ + Elf_Half get_hash_table_index() const { return hash_section_index; } + + //------------------------------------------------------------------------------ + bool hash_lookup( const std::string& name, + Elf64_Addr& value, + Elf_Xword& size, + unsigned char& bind, + unsigned char& type, + Elf_Half& section_index, + unsigned char& other ) const + { + bool ret = false; + const endianess_convertor& convertor = elf_file.get_convertor(); + + Elf_Word nbucket = *(const Elf_Word*)hash_section->get_data(); + nbucket = convertor( nbucket ); + Elf_Word nchain = + *(const Elf_Word*)( hash_section->get_data() + sizeof( Elf_Word ) ); + nchain = convertor( nchain ); + Elf_Word val = elf_hash( (const unsigned char*)name.c_str() ); + Elf_Word y = + *(const Elf_Word*)( hash_section->get_data() + + ( 2 + val % nbucket ) * sizeof( Elf_Word ) ); + y = convertor( y ); + std::string str; + get_symbol( y, str, value, size, bind, type, section_index, other ); + while ( str != name && STN_UNDEF != y && y < nchain ) { + y = *(const Elf_Word*)( hash_section->get_data() + + ( 2 + nbucket + y ) * sizeof( Elf_Word ) ); + y = convertor( y ); + get_symbol( y, str, value, size, bind, type, section_index, other ); + } + + if ( str == name ) { + ret = true; + } + + return ret; + } + + //------------------------------------------------------------------------------ + template + bool gnu_hash_lookup( const std::string& name, + Elf64_Addr& value, + Elf_Xword& size, + unsigned char& bind, + unsigned char& type, + Elf_Half& section_index, + unsigned char& other ) const + { + bool ret = false; + const endianess_convertor& convertor = elf_file.get_convertor(); + + uint32_t nbuckets = *( (uint32_t*)hash_section->get_data() + 0 ); + uint32_t symoffset = *( (uint32_t*)hash_section->get_data() + 1 ); + uint32_t bloom_size = *( (uint32_t*)hash_section->get_data() + 2 ); + uint32_t bloom_shift = *( (uint32_t*)hash_section->get_data() + 3 ); + nbuckets = convertor( nbuckets ); + symoffset = convertor( symoffset ); + bloom_size = convertor( bloom_size ); + bloom_shift = convertor( bloom_shift ); + + T* bloom_filter = + (T*)( hash_section->get_data() + 4 * sizeof( uint32_t ) ); + + uint32_t hash = elf_gnu_hash( (const unsigned char*)name.c_str() ); + uint32_t bloom_index = ( hash / ( 8 * sizeof( T ) ) ) % bloom_size; + T bloom_bits = + ( (T)1 << ( hash % ( 8 * sizeof( T ) ) ) ) | + ( (T)1 << ( ( hash >> bloom_shift ) % ( 8 * sizeof( T ) ) ) ); + + if ( ( convertor( bloom_filter[bloom_index] ) & bloom_bits ) == + bloom_bits ) { + uint32_t bucket = hash % nbuckets; + auto* buckets = + (uint32_t*)( hash_section->get_data() + 4 * sizeof( uint32_t ) + + bloom_size * sizeof( T ) ); + auto* chains = + (uint32_t*)( hash_section->get_data() + 4 * sizeof( uint32_t ) + + bloom_size * sizeof( T ) + + nbuckets * sizeof( uint32_t ) ); + + if ( convertor( buckets[bucket] ) >= symoffset ) { + uint32_t chain_index = convertor( buckets[bucket] ) - symoffset; + uint32_t chain_hash = convertor( chains[chain_index] ); + std::string symname; + while ( true ) { + if ( ( chain_hash >> 1 ) == ( hash >> 1 ) && + get_symbol( chain_index + symoffset, symname, value, + size, bind, type, section_index, other ) && + name == symname ) { + ret = true; + break; + } + + if ( chain_hash & 1 ) + break; + chain_hash = convertor( chains[++chain_index] ); + } + } + } + + return ret; + } + + //------------------------------------------------------------------------------ + template const T* generic_get_symbol_ptr( Elf_Xword index ) const + { + if ( 0 != symbol_section->get_data() && index < get_symbols_num() ) { + const T* pSym = reinterpret_cast( + symbol_section->get_data() + + index * symbol_section->get_entry_size() ); + + return pSym; + } + + return nullptr; + } + + //------------------------------------------------------------------------------ + template + bool generic_search_symbols( std::function match, + Elf_Xword& idx ) const + { + for ( Elf_Xword i = 0; i < get_symbols_num(); i++ ) { + const T* symPtr = generic_get_symbol_ptr( i ); + + if ( symPtr == nullptr ) + return false; + + if ( match( symPtr ) ) { + idx = i; + return true; + } + } + + return false; + } + + //------------------------------------------------------------------------------ + template + bool generic_get_symbol( Elf_Xword index, + std::string& name, + Elf64_Addr& value, + Elf_Xword& size, + unsigned char& bind, + unsigned char& type, + Elf_Half& section_index, + unsigned char& other ) const + { + bool ret = false; + + if ( nullptr != symbol_section->get_data() && + index < get_symbols_num() ) { + const T* pSym = reinterpret_cast( + symbol_section->get_data() + + index * symbol_section->get_entry_size() ); + + const endianess_convertor& convertor = elf_file.get_convertor(); + + section* string_section = + elf_file.sections[get_string_table_index()]; + string_section_accessor str_reader( string_section ); + const char* pStr = + str_reader.get_string( convertor( pSym->st_name ) ); + if ( nullptr != pStr ) { + name = pStr; + } + value = convertor( pSym->st_value ); + size = convertor( pSym->st_size ); + bind = ELF_ST_BIND( pSym->st_info ); + type = ELF_ST_TYPE( pSym->st_info ); + section_index = convertor( pSym->st_shndx ); + other = pSym->st_other; + + ret = true; + } + + return ret; + } + + //------------------------------------------------------------------------------ + template + Elf_Word generic_add_symbol( Elf_Word name, + Elf64_Addr value, + Elf_Xword size, + unsigned char info, + unsigned char other, + Elf_Half shndx ) + { + const endianess_convertor& convertor = elf_file.get_convertor(); + + T entry; + entry.st_name = convertor( name ); + entry.st_value = value; + entry.st_value = convertor( entry.st_value ); + entry.st_size = size; + entry.st_size = convertor( entry.st_size ); + entry.st_info = convertor( info ); + entry.st_other = convertor( other ); + entry.st_shndx = convertor( shndx ); + + symbol_section->append_data( reinterpret_cast( &entry ), + sizeof( entry ) ); + + Elf_Word nRet = symbol_section->get_size() / sizeof( entry ) - 1; + + return nRet; + } + + //------------------------------------------------------------------------------ + template + Elf_Xword generic_arrange_local_symbols( + std::function func ) + { + const endianess_convertor& convertor = elf_file.get_convertor(); + + Elf_Xword first_not_local = + 1; // Skip the first entry. It is always NOTYPE + Elf_Xword current = 0; + Elf_Xword count = get_symbols_num(); + + while ( true ) { + T* p1 = nullptr; + T* p2 = nullptr; + + while ( first_not_local < count ) { + p1 = const_cast( + generic_get_symbol_ptr( first_not_local ) ); + if ( ELF_ST_BIND( convertor( p1->st_info ) ) != STB_LOCAL ) + break; + ++first_not_local; + } + + current = first_not_local + 1; + while ( current < count ) { + p2 = const_cast( generic_get_symbol_ptr( current ) ); + if ( ELF_ST_BIND( convertor( p2->st_info ) ) == STB_LOCAL ) + break; + ++current; + } + + if ( first_not_local < count && current < count ) { + if ( func ) + func( first_not_local, current ); + + std::swap( *p1, *p2 ); + } + else { + // Update 'info' field of the section + symbol_section->set_info( first_not_local ); + break; + } + } + + // Elf_Word nRet = symbol_section->get_size() / sizeof(entry) - 1; + + return first_not_local; + } + + //------------------------------------------------------------------------------ + private: + const elfio& elf_file; + S* symbol_section; + Elf_Half hash_section_index; + const section* hash_section; +}; + +using symbol_section_accessor = symbol_section_accessor_template
; +using const_symbol_section_accessor = + symbol_section_accessor_template; + +} // namespace ELFIO + +#endif // ELFIO_SYMBOLS_HPP diff --git a/tools/elfio/elfio_utils.hpp b/tools/elfio/elfio_utils.hpp new file mode 100644 index 00000000000..5e9c55b32dd --- /dev/null +++ b/tools/elfio/elfio_utils.hpp @@ -0,0 +1,266 @@ +/* +Copyright (C) 2001-present by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELFIO_UTILS_HPP +#define ELFIO_UTILS_HPP + +#include +#include + +#define ELFIO_GET_ACCESS_DECL( TYPE, NAME ) virtual TYPE get_##NAME() const = 0 + +#define ELFIO_SET_ACCESS_DECL( TYPE, NAME ) \ + virtual void set_##NAME( TYPE value ) = 0 + +#define ELFIO_GET_SET_ACCESS_DECL( TYPE, NAME ) \ + virtual TYPE get_##NAME() const = 0; \ + virtual void set_##NAME( TYPE value ) = 0 + +#define ELFIO_GET_ACCESS( TYPE, NAME, FIELD ) \ + TYPE get_##NAME() const override { return ( *convertor )( FIELD ); } + +#define ELFIO_SET_ACCESS( TYPE, NAME, FIELD ) \ + void set_##NAME( TYPE value ) override \ + { \ + FIELD = value; \ + FIELD = ( *convertor )( FIELD ); \ + } +#define ELFIO_GET_SET_ACCESS( TYPE, NAME, FIELD ) \ + TYPE get_##NAME() const override { return ( *convertor )( FIELD ); } \ + void set_##NAME( TYPE value ) override \ + { \ + FIELD = value; \ + FIELD = ( *convertor )( FIELD ); \ + } + +namespace ELFIO { + +//------------------------------------------------------------------------------ +class endianess_convertor +{ + public: + //------------------------------------------------------------------------------ + endianess_convertor() { need_conversion = false; } + + //------------------------------------------------------------------------------ + void setup( unsigned char elf_file_encoding ) + { + need_conversion = ( elf_file_encoding != get_host_encoding() ); + } + + //------------------------------------------------------------------------------ + uint64_t operator()( uint64_t value ) const + { + if ( !need_conversion ) { + return value; + } + value = ( ( value & 0x00000000000000FFull ) << 56 ) | + ( ( value & 0x000000000000FF00ull ) << 40 ) | + ( ( value & 0x0000000000FF0000ull ) << 24 ) | + ( ( value & 0x00000000FF000000ull ) << 8 ) | + ( ( value & 0x000000FF00000000ull ) >> 8 ) | + ( ( value & 0x0000FF0000000000ull ) >> 24 ) | + ( ( value & 0x00FF000000000000ull ) >> 40 ) | + ( ( value & 0xFF00000000000000ull ) >> 56 ); + + return value; + } + + //------------------------------------------------------------------------------ + int64_t operator()( int64_t value ) const + { + if ( !need_conversion ) { + return value; + } + return (int64_t)(*this)( (uint64_t)value ); + } + + //------------------------------------------------------------------------------ + uint32_t operator()( uint32_t value ) const + { + if ( !need_conversion ) { + return value; + } + value = + ( ( value & 0x000000FF ) << 24 ) | ( ( value & 0x0000FF00 ) << 8 ) | + ( ( value & 0x00FF0000 ) >> 8 ) | ( ( value & 0xFF000000 ) >> 24 ); + + return value; + } + + //------------------------------------------------------------------------------ + int32_t operator()( int32_t value ) const + { + if ( !need_conversion ) { + return value; + } + return (int32_t)(*this)( (uint32_t)value ); + } + + //------------------------------------------------------------------------------ + uint16_t operator()( uint16_t value ) const + { + if ( !need_conversion ) { + return value; + } + value = ( ( value & 0x00FF ) << 8 ) | ( ( value & 0xFF00 ) >> 8 ); + + return value; + } + + //------------------------------------------------------------------------------ + int16_t operator()( int16_t value ) const + { + if ( !need_conversion ) { + return value; + } + return (int16_t)(*this)( (uint16_t)value ); + } + + //------------------------------------------------------------------------------ + int8_t operator()( int8_t value ) const { return value; } + + //------------------------------------------------------------------------------ + uint8_t operator()( uint8_t value ) const { return value; } + + //------------------------------------------------------------------------------ + private: + //------------------------------------------------------------------------------ + unsigned char get_host_encoding() const + { + static const int tmp = 1; + if ( 1 == *reinterpret_cast( &tmp ) ) { + return ELFDATA2LSB; + } + else { + return ELFDATA2MSB; + } + } + + //------------------------------------------------------------------------------ + bool need_conversion; +}; + +//------------------------------------------------------------------------------ +struct address_translation +{ + address_translation( uint64_t start, uint64_t size, uint64_t mapped_to ) + : start( start ), size( size ), mapped_to( mapped_to ){}; + std::streampos start; + std::streampos size; + std::streampos mapped_to; +}; + +//------------------------------------------------------------------------------ +class address_translator +{ + public: + //------------------------------------------------------------------------------ + void set_address_translation( std::vector& addr_trans ) + { + addr_translations = addr_trans; + + std::sort( + addr_translations.begin(), addr_translations.end(), + []( address_translation& a, address_translation& b ) -> bool { + return a.start < b.start; + } ); + } + + //------------------------------------------------------------------------------ + std::streampos operator[]( std::streampos value ) const + { + if ( addr_translations.empty() ) { + return value; + } + + for ( auto& t : addr_translations ) { + if ( ( t.start <= value ) && ( ( value - t.start ) < t.size ) ) { + return value - t.start + t.mapped_to; + } + } + + return value; + } + + bool empty() const { return addr_translations.empty(); } + + private: + std::vector addr_translations; +}; + +//------------------------------------------------------------------------------ +inline uint32_t elf_hash( const unsigned char* name ) +{ + uint32_t h = 0, g = 0; + while ( *name != '\0' ) { + h = ( h << 4 ) + *name++; + g = h & 0xf0000000; + if ( g != 0 ) + h ^= g >> 24; + h &= ~g; + } + return h; +} + +//------------------------------------------------------------------------------ +inline uint32_t elf_gnu_hash( const unsigned char* s ) +{ + uint32_t h = 0x1505; + for ( unsigned char c = *s; c != '\0'; c = *++s ) + h = ( h << 5 ) + h + c; + return h; +} + +//------------------------------------------------------------------------------ +inline std::string to_hex_string( uint64_t value ) +{ + std::string str; + + while ( value ) { + auto digit = value & 0xF; + if ( digit < 0xA ) { + str = char( '0' + digit ) + str; + } + else { + str = char( 'A' + digit - 0xA ) + str; + } + value >>= 4; + } + + return "0x" + str; +} + +//------------------------------------------------------------------------------ +inline void adjust_stream_size( std::ostream& stream, std::streamsize offset ) +{ + stream.seekp( 0, std::ios_base::end ); + if ( stream.tellp() < offset ) { + std::streamsize size = offset - stream.tellp(); + stream.write( std::string( size, '\0' ).c_str(), size ); + } + stream.seekp( offset ); +} + +} // namespace ELFIO + +#endif // ELFIO_UTILS_HPP diff --git a/tools/elfio/elfio_version.hpp b/tools/elfio/elfio_version.hpp new file mode 100644 index 00000000000..c7b161c30dc --- /dev/null +++ b/tools/elfio/elfio_version.hpp @@ -0,0 +1 @@ +#define ELFIO_VERSION "3.10" diff --git a/tools/elfio/elfio_versym.hpp b/tools/elfio/elfio_versym.hpp new file mode 100644 index 00000000000..6e99877c86e --- /dev/null +++ b/tools/elfio/elfio_versym.hpp @@ -0,0 +1,177 @@ +/* +Copyright (C) 2001-present by Serge Lamikhov-Center + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef ELFIO_VERSYM_HPP +#define ELFIO_VERSYM_HPP + +namespace ELFIO { + +//------------------------------------------------------------------------------ +template class versym_section_accessor_template +{ + public: + //------------------------------------------------------------------------------ + versym_section_accessor_template( S* section ) : versym_section( section ) + { + if ( section ) { + entries_num = section->get_size() / sizeof( Elf_Half ); + } + } + + //------------------------------------------------------------------------------ + Elf_Word get_entries_num() const + { + if ( versym_section ) { + return entries_num; + } + return 0; + } + + //------------------------------------------------------------------------------ + bool get_entry( Elf_Word no, Elf_Half& value ) const + { + if ( versym_section && ( no < get_entries_num() ) ) { + value = ( (Elf_Half*)versym_section->get_data() )[no]; + return true; + } + + return false; + } + + //------------------------------------------------------------------------------ + bool modify_entry( Elf_Word no, Elf_Half value ) + { + if ( versym_section && ( no < get_entries_num() ) ) { + ( (Elf_Half*)versym_section->get_data() )[no] = value; + return true; + } + + return false; + } + + //------------------------------------------------------------------------------ + bool add_entry( Elf_Half value ) + { + if ( !versym_section ) { + return false; + } + + versym_section->append_data( (const char*)&value, sizeof( Elf_Half ) ); + ++entries_num; + + return true; + } + + //------------------------------------------------------------------------------ + private: + S* versym_section; + Elf_Word entries_num; +}; + +using versym_section_accessor = versym_section_accessor_template
; +using const_versym_section_accessor = + versym_section_accessor_template; + +//------------------------------------------------------------------------------ +template class versym_r_section_accessor_template +{ + public: + //------------------------------------------------------------------------------ + versym_r_section_accessor_template( const elfio& elf_file, + S* versym_r_section ) + : elf_file( elf_file ), versym_r_section( versym_r_section ), + entries_num( 0 ) + { + // Find .dynamic section + const section* dynamic_section = elf_file.sections[".dynamic"]; + + if ( dynamic_section == nullptr ) { + return; + } + + const_dynamic_section_accessor dynamic_section_acc( elf_file, + dynamic_section ); + Elf_Xword dyn_sec_num = dynamic_section_acc.get_entries_num(); + for ( Elf_Xword i = 0; i < dyn_sec_num; ++i ) { + Elf_Xword tag; + Elf_Xword value; + std::string str; + + if ( dynamic_section_acc.get_entry( i, tag, value, str ) && + tag == DT_VERNEEDNUM ) { + entries_num = value; + break; + } + } + } + + //------------------------------------------------------------------------------ + Elf_Word get_entries_num() const { return entries_num; } + + //------------------------------------------------------------------------------ + bool get_entry( Elf_Word no, + Elf_Half& version, + std::string& file_name, + Elf_Word& hash, + Elf_Half& flags, + Elf_Half& other, + std::string& dep_name ) const + { + if ( versym_r_section == nullptr || ( no >= get_entries_num() ) ) { + return false; + } + + const_string_section_accessor string_section_acc( + elf_file.sections[versym_r_section->get_link()] ); + + Elfxx_Verneed* verneed = (Elfxx_Verneed*)versym_r_section->get_data(); + Elfxx_Vernaux* veraux = + (Elfxx_Vernaux*)( (char*)verneed + verneed->vn_aux ); + for ( Elf_Word i = 0; i < no; ++i ) { + verneed = (Elfxx_Verneed*)( (char*)verneed + verneed->vn_next ); + veraux = (Elfxx_Vernaux*)( (char*)verneed + verneed->vn_aux ); + } + + version = verneed->vn_version; + file_name = string_section_acc.get_string( verneed->vn_file ); + hash = veraux->vna_hash; + flags = veraux->vna_flags; + other = veraux->vna_other; + dep_name = string_section_acc.get_string( veraux->vna_name ); + + return true; + } + + //------------------------------------------------------------------------------ + private: + const elfio& elf_file; + S* versym_r_section; + Elf_Word entries_num; +}; + +using versym_r_section_accessor = versym_r_section_accessor_template
; +using const_versym_r_section_accessor = + versym_r_section_accessor_template; + +} // namespace ELFIO + +#endif // ELFIO_VERSYM_HPP diff --git a/tools/sdk-tools/README.md b/tools/sdk-tools/README.md new file mode 100644 index 00000000000..b40c45186bc --- /dev/null +++ b/tools/sdk-tools/README.md @@ -0,0 +1,2 @@ +# sdk-tools +Decompilation of the Nintendo 64 SDK developer tools diff --git a/tools/sdk-tools/adpcm/.gitignore b/tools/sdk-tools/adpcm/.gitignore new file mode 100644 index 00000000000..d5eb0e7adbf --- /dev/null +++ b/tools/sdk-tools/adpcm/.gitignore @@ -0,0 +1,12 @@ +*.o +*.s +*.dump +*.aiff +*.aifc +*.table +/vadpcm_dec_irix +/vadpcm_enc_irix +/vadpcm_dec_native +/vadpcm_enc_native +/vadpcm_dec_orig +/vadpcm_enc_orig diff --git a/tools/sdk-tools/adpcm/Makefile b/tools/sdk-tools/adpcm/Makefile new file mode 100644 index 00000000000..b97991bee6f --- /dev/null +++ b/tools/sdk-tools/adpcm/Makefile @@ -0,0 +1,39 @@ +# Makefile for building vadpcm_enc and vadpcm_dec for either IRIX or natively. +# For an IRIX build, the env variable IRIX_ROOT should point to the root of an +# IRIX filesystem, and QEMU_IRIX should point to the qemu-irix binary. + +IRIX_CC := $(QEMU_IRIX) -silent -L $(IRIX_ROOT) $(IRIX_ROOT)/usr/bin/cc +IRIX_CFLAGS := -fullwarn -woff 515,608,658,799 -Wab,-r4300_mul -g -Xcpluscomm -mips1 -o32 + +NATIVE_CC := gcc +NATIVE_CFLAGS := -g -Wall -O2 -Wno-unused-result -Wno-uninitialized + +default: native +all: irix native + +irix: vadpcm_dec_irix vadpcm_enc_irix +native: vadpcm_dec_native vadpcm_enc_native + +clean: + $(RM) *.o vadpcm_dec_irix vadpcm_enc_irix vadpcm_dec_native vadpcm_enc_native + +%.o: %.c + $(IRIX_CC) -c $(IRIX_CFLAGS) $< -o $@ + +vadpcm_dec_irix: SHELL := /usr/bin/env bash +vadpcm_dec_irix: vadpcm_dec.o vpredictor.o sampleio.o vdecode.o util.o + $(IRIX_CC) $^ -o $@ -lm + @dd status=none iflag=skip_bytes,count_bytes skip=$$((0x120)) count=$$((0x5000 - 0x120)) if=$@ | sha256sum | diff -q - <(echo 'ffaf4d0e4a5d13279d8de8e1eb4ba0f6350e7e3940ad1339f665036bf74f81c1 -') >/dev/null && echo $@: OK || echo $@: FAILED + +vadpcm_enc_irix: SHELL := /usr/bin/env bash +vadpcm_enc_irix: vadpcm_enc.o vpredictor.o quant.o util.o vencode.o + $(IRIX_CC) $^ -o $@ -lm + @dd status=none iflag=skip_bytes,count_bytes skip=$$((0x120)) count=$$((0x6000 - 0x120)) if=$@ | sha256sum | diff -q - <(echo '803be21f985c520eafdde0ff2d0ad2d6dd0db364f146c6d5f5763251f4c1796b -') >/dev/null && echo $@: OK || echo $@: FAILED + +vadpcm_dec_native: vadpcm_dec.c vpredictor.c sampleio.c vdecode.c util.c + $(NATIVE_CC) $(NATIVE_CFLAGS) $^ -o $@ -lm + +vadpcm_enc_native: vadpcm_enc.c vpredictor.c quant.c util.c vencode.c + $(NATIVE_CC) $(NATIVE_CFLAGS) $^ -o $@ -lm + +.PHONY: default all irix native clean diff --git a/tools/sdk-tools/adpcm/quant.c b/tools/sdk-tools/adpcm/quant.c new file mode 100644 index 00000000000..e67ccbf44b4 --- /dev/null +++ b/tools/sdk-tools/adpcm/quant.c @@ -0,0 +1,70 @@ +#include "vadpcm.h" + +/** + * Compute x / scale rounded to the nearest integer, with x.5 (fuzzy with an + * epsilon of 1e-7) rounding towards zero. + */ +s16 qsample(f32 x, s32 scale) +{ + if (x > 0.0f) + { + return (s16) ((x / scale) + 0.4999999); + } + else + { + return (s16) ((x / scale) - 0.4999999); + } +} + +/** + * Round all ('fs' many) values in 'e' to the nearest 'bits'-bit integer, + * outputting to 'ie'. + */ +void clamp(s32 fs, f32 *e, s32 *ie, s32 bits) +{ + s32 i; + f32 ulevel; + f32 llevel; + + llevel = -(f32) (1 << (bits - 1)); + ulevel = -llevel - 1.0f; + for (i = 0; i < fs; i++) + { + if (e[i] > ulevel) + { + e[i] = ulevel; + } + if (e[i] < llevel) + { + e[i] = llevel; + } + + if (e[i] > 0.0f) + { + ie[i] = (s32) (e[i] + 0.5); + } + else + { + ie[i] = (s32) (e[i] - 0.5); + } + } +} + +/** + * Clamp ix to within [llevel, ulevel]. + */ +s32 clip(s32 ix, s32 llevel, s32 ulevel) +{ + if (ix < llevel || ix > ulevel) + { + if (ix < llevel) + { + return llevel; + } + if (ix > ulevel) + { + return ulevel; + } + } + return ix; +} diff --git a/tools/sdk-tools/adpcm/sampleio.c b/tools/sdk-tools/adpcm/sampleio.c new file mode 100644 index 00000000000..08187ff7683 --- /dev/null +++ b/tools/sdk-tools/adpcm/sampleio.c @@ -0,0 +1,63 @@ +#include +#include +#include "vadpcm.h" + +static void fmtchan(s32 size, u8 *p, s32 *data, s32 stride) +{ + s32 i; + s32 c; + + for (i = 0; i < size; i++) + { + c = *data++; + if (c < -0x7fff) + { + c = -0x7fff; + } + if (c >= 0x8000) + { + c = 0x7fff; + } + p[0] = c >> 8; + p[1] = c; + p += stride; + } +} + +void writeout(FILE *outfd, s32 size, s32 *l_out, s32 *r_out, s32 chans) +{ + static u8 obuf[0x1000]; + s32 i; + + switch (chans) + { + case 2: + fmtchan(size, obuf, l_out, chans * 2); + fmtchan(size, obuf + 2, r_out, chans * 2); + if (outfd != NULL) + { + if ((i = fwrite(obuf, 1, size * 4, outfd)) != size * 4) + { + fprintf(stderr, "write error %d\n", i); + exit(1); + } + } + break; + + case 1: + fmtchan(size, obuf, l_out, 2); + if (outfd != NULL) + { + if ((i = fwrite(obuf, 1, size * 2, outfd)) != size * 2) + { + fprintf(stderr, "write error %d\n", i); + exit(1); + } + } + break; + + default: + fprintf(stderr, "Error in number of channels\n"); + exit(1); + } +} diff --git a/tools/sdk-tools/adpcm/util.c b/tools/sdk-tools/adpcm/util.c new file mode 100644 index 00000000000..22acdd76865 --- /dev/null +++ b/tools/sdk-tools/adpcm/util.c @@ -0,0 +1,106 @@ +#include +#include +#include "vadpcm.h" + +static s32 input_word = 0; +static s32 in_bit_pos = -1; + +static u32 getshort(FILE *ifile) +{ + u32 c1; + u32 c2; + + if ((c1 = getc(ifile)) == -1) + { + return 0; + } + + if ((c2 = getc(ifile)) == -1) + { + return 0; + } + + return (c1 << 8) | c2; +} + +u32 readbits(u32 nbits, FILE *ifile) +{ + u32 c; + u32 b; + u32 left; + u32 mask; + + if (nbits <= in_bit_pos + 1) + { + mask = (1U << nbits) - 1; + b = ((u32) input_word >> (in_bit_pos - nbits + 1)) & mask; + in_bit_pos -= nbits; + if (in_bit_pos < 0) + { + c = getshort(ifile); + input_word = c; + in_bit_pos = 15; + } + return b; + } + else + { + b = input_word & ((1U << (in_bit_pos + 1)) - 1); + left = nbits - in_bit_pos - 1; + c = getshort(ifile); + input_word = c; + in_bit_pos = 15; + b = readbits(left, ifile) | (b << left); + return b; + } +} + +char *ReadPString(FILE *ifile) +{ + u8 c; + char *st; + + fread(&c, 1, 1, ifile); + st = malloc(c + 1); + fread(st, c, 1, ifile); + st[c] = '\0'; + if ((c & 1) == 0) + { + fread(&c, 1, 1, ifile); + } + return st; +} + +s32 lookupMarker(u32 *sample, s16 loopPoint, Marker *markers, s32 nmarkers) +{ + s32 i; + + for (i = 0; i < nmarkers; i++) + { + if (markers[i].MarkerID == loopPoint) + { + *sample = (markers[i].positionH << 16) + markers[i].positionL; + return 0; + } + } + return 1; +} + +ALADPCMloop *readlooppoints(FILE *ifile, s16 *nloops) +{ + s32 i; + ALADPCMloop *al; + + fread(nloops, sizeof(s16), 1, ifile); + BSWAP16(*nloops) + al = malloc(*nloops * sizeof(ALADPCMloop)); + for (i = 0; i < *nloops; i++) + { + fread(&al[i], sizeof(ALADPCMloop), 1, ifile); + BSWAP32(al[i].start) + BSWAP32(al[i].end) + BSWAP32(al[i].count) + BSWAP16_MANY(al[i].state, 16) + } + return al; +} diff --git a/tools/sdk-tools/adpcm/vadpcm.h b/tools/sdk-tools/adpcm/vadpcm.h new file mode 100644 index 00000000000..cac44861857 --- /dev/null +++ b/tools/sdk-tools/adpcm/vadpcm.h @@ -0,0 +1,124 @@ +#ifndef VADPCM_H +#define VADPCM_H + +#include + +typedef signed char s8; +typedef short s16; +typedef int s32; +typedef long long s64; +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; +typedef unsigned long long u64; +typedef float f32; +typedef double f64; + +#ifdef __sgi +# define BSWAP16(x) +# define BSWAP32(x) +# define BSWAP16_MANY(x, n) +#else +# define BSWAP16(x) x = __builtin_bswap16(x); +# define BSWAP32(x) x = __builtin_bswap32(x); +# define BSWAP16_MANY(x, n) { s32 _i; for (_i = 0; _i < n; _i++) BSWAP16((x)[_i]) } +#endif + +#ifdef __sgi +# define MODE_READ "r" +# define MODE_WRITE "w" +#else +# define MODE_READ "rb" +# define MODE_WRITE "wb" +#endif + +typedef struct { + u32 ckID; + u32 ckSize; +} ChunkHeader; + +typedef struct { + u32 ckID; + u32 ckSize; + u32 formType; +} Chunk; + +typedef struct { + s16 numChannels; + u16 numFramesH; + u16 numFramesL; + s16 sampleSize; + s16 sampleRate[5]; // 80-bit float + u16 compressionTypeH; + u16 compressionTypeL; +} CommonChunk; + +typedef struct { + s16 MarkerID; + u16 positionH; + u16 positionL; +} Marker; + +typedef struct { + s16 playMode; + s16 beginLoop; + s16 endLoop; +} Loop; + +typedef struct { + s8 baseNote; + s8 detune; + s8 lowNote; + s8 highNote; + s8 lowVelocity; + s8 highVelocity; + s16 gain; + Loop sustainLoop; + Loop releaseLoop; +} InstrumentChunk; + +typedef struct { + s32 offset; + s32 blockSize; +} SoundDataChunk; + +typedef struct { + s16 version; + s16 order; + s16 nEntries; +} CodeChunk; + +typedef struct +{ + u32 start; + u32 end; + u32 count; + s16 state[16]; +} ALADPCMloop; + +// vpredictor.c +s32 readcodebook(FILE *fhandle, s32 ****table, s32 *order, s32 *npredictors); +s32 readaifccodebook(FILE *fhandle, s32 ****table, s16 *order, s16 *npredictors); +s32 inner_product(s32 length, s32 *v1, s32 *v2); + +// quant.c +s16 qsample(f32 x, s32 scale); +void clamp(s32 fs, f32 *e, s32 *ie, s32 bits); +s32 clip(s32 ix, s32 llevel, s32 ulevel); + +// vdecode.c +void vdecodeframe(FILE *ifile, s32 *outp, s32 order, s32 ***coefTable); + +// vencode.c +void vencodeframe(FILE *ofile, s16 *inBuffer, s32 *state, s32 ***coefTable, s32 order, s32 npredictors, s32 nsam); + +// util.c +u32 readbits(u32 nbits, FILE *ifile); +char *ReadPString(FILE *ifile); +s32 lookupMarker(u32 *sample, s16 loopPoint, Marker *markers, s32 nmarkers); +ALADPCMloop *readlooppoints(FILE *ifile, s16 *nloops); + +// sampleio.c +void writeout(FILE *outfd, s32 size, s32 *l_out, s32 *r_out, s32 chans); + +#endif diff --git a/tools/sdk-tools/adpcm/vadpcm_dec.c b/tools/sdk-tools/adpcm/vadpcm_dec.c new file mode 100644 index 00000000000..95d445972d1 --- /dev/null +++ b/tools/sdk-tools/adpcm/vadpcm_dec.c @@ -0,0 +1,301 @@ +#include +#include +#include +#include +#include +#include +#include +#include "vadpcm.h" + +static void int_handler(s32 sig) +{ + s32 flags; + + flags = fcntl(STDIN_FILENO, F_GETFL, 0); + flags &= ~FNDELAY; + fcntl(STDIN_FILENO, F_SETFL, flags); + exit(0); +} + +static char usage[] = "bitfile"; + +#ifdef __sgi + +// Declaring a sigaction like this is wildly unportable; you're supposed to +// assign members one by one in code. We do that in the non-SGI case. +static struct sigaction int_act = { + /* sa_flags = */ SA_RESTART, + /* sa_handler = */ &int_handler, + /* sa_mask = */ 0, +}; + +#endif + +s32 main(s32 argc, char **argv) +{ + s32 c; + u8 cc; + u8 doloop = 0; + s16 order; + s16 version; + s16 nloops; + s16 npredictors; + s32 flags; + s32 ***coefTable = NULL; + s32 i; + s32 j; + s32 *outp; + s32 *state; + s32 done = 0; + s32 num; + u32 ts; + s32 soundPointer; + s32 cType; + s32 offset; + s32 currPos = 0; + s32 nSamples; + s32 framePos; + s32 loopBegin; + s32 left; + ALADPCMloop *aloops; + Chunk FormChunk; + ChunkHeader Header; + CommonChunk CommChunk; + SoundDataChunk SndDChunk; + char *ChunkName; + FILE *ifile; + char *progname = argv[0]; + +#ifndef __sgi + nloops = 0; +#endif + + if (argc < 2) + { + fprintf(stderr, "%s %s\n", progname, usage); + exit(1); + } + + while ((c = getopt(argc, argv, "l")) != -1) + { + switch (c) + { + case 'l': + doloop = 1; + break; + } + } + + argv += optind - 1; + if ((ifile = fopen(argv[1], MODE_READ)) == NULL) + { + fprintf(stderr, "%s: bitstream file [%s] could not be opened\n", progname, argv[1]); + exit(1); + } + + state = malloc(16 * sizeof(int)); + for (i = 0; i < 16; i++) + { + state[i] = 0; + } + + fread(&FormChunk, sizeof(FormChunk), 1, ifile); + BSWAP32(FormChunk.ckID) + BSWAP32(FormChunk.formType) + if ((FormChunk.ckID != 0x464f524d) || (FormChunk.formType != 0x41494643)) // FORM, AIFC + { + fprintf(stderr, "%s: [%s] is not an AIFF-C File\n", progname, argv[1]); + exit(1); + } + + while (!done) + { + num = fread(&Header, sizeof(Header), 1, ifile); + if (num <= 0) + { + done = 1; + break; + } + BSWAP32(Header.ckID) + BSWAP32(Header.ckSize) + + Header.ckSize++, Header.ckSize &= ~1; + switch (Header.ckID) + { + case 0x434f4d4d: // COMM + offset = ftell(ifile); + num = fread(&CommChunk, sizeof(CommChunk), 1, ifile); + if (num <= 0) + { + fprintf(stderr, "%s: error parsing file [%s]\n", progname, argv[1]); + done = 1; + } + BSWAP16(CommChunk.numChannels) + BSWAP16(CommChunk.numFramesH) + BSWAP16(CommChunk.numFramesL) + BSWAP16(CommChunk.sampleSize) + BSWAP16(CommChunk.compressionTypeH) + BSWAP16(CommChunk.compressionTypeL) + cType = (CommChunk.compressionTypeH << 16) + CommChunk.compressionTypeL; + if (cType != 0x56415043) // VAPC + { + fprintf(stderr, "%s: file [%s] is of the wrong compression type.\n", progname, argv[1]); + exit(1); + } + if (CommChunk.numChannels != 1) + { + fprintf(stderr, "%s: file [%s] contains %ld channels, only 1 channel supported.\n", progname, argv[1], (long) CommChunk.numChannels); + exit(1); + } + if (CommChunk.sampleSize != 16) + { + fprintf(stderr, "%s: file [%s] contains %ld bit samples, only 16 bit samples supported.\n", progname, argv[1], (long) CommChunk.sampleSize); + exit(1); + } + nSamples = (CommChunk.numFramesH << 16) + CommChunk.numFramesL; + fseek(ifile, offset + Header.ckSize, SEEK_SET); + break; + + case 0x53534e44: // SSND + offset = ftell(ifile); + fread(&SndDChunk, sizeof(SndDChunk), 1, ifile); + BSWAP32(SndDChunk.offset) + BSWAP32(SndDChunk.blockSize) + // The assert error messages specify line numbers 165/166. Match + // that using a #line directive. +#ifdef __sgi +# line 164 +#endif + assert(SndDChunk.offset == 0); + assert(SndDChunk.blockSize == 0); + soundPointer = ftell(ifile); + fseek(ifile, offset + Header.ckSize, SEEK_SET); + break; + + case 0x4150504c: // APPL + offset = ftell(ifile); + fread(&ts, sizeof(u32), 1, ifile); + BSWAP32(ts) + if (ts == 0x73746f63) // stoc + { + ChunkName = ReadPString(ifile); + if (strcmp("VADPCMCODES", ChunkName) == 0) + { + fread(&version, sizeof(s16), 1, ifile); + BSWAP16(version) + if (version != 1) + { + fprintf(stderr, "Non-identical codebook chunk versions\n"); + } + readaifccodebook(ifile, &coefTable, &order, &npredictors); + } + else if (strcmp("VADPCMLOOPS", ChunkName) == 0) + { + fread(&version, sizeof(s16), 1, ifile); + BSWAP16(version) + if (version != 1) + { + fprintf(stderr, "Non-identical loop chunk versions\n"); + } + aloops = readlooppoints(ifile, &nloops); + } + } + fseek(ifile, offset + Header.ckSize, SEEK_SET); + break; + + default: + // We don't understand this chunk. Skip it. + fseek(ifile, Header.ckSize, SEEK_CUR); + break; + } + } + + if (coefTable == NULL) + { + // @bug should use progname; argv[0] may be an option + fprintf(stderr, "%s: Codebook missing from bitstream [%s]\n", argv[0], argv[1]); + exit(1); + } + + outp = malloc(16 * sizeof(s32)); + for (i = 0; i < order; i++) + { + outp[15 - i] = 0; + } + + fseek(ifile, soundPointer, SEEK_SET); + if (doloop && nloops > 0) + { +#ifndef __sgi + struct sigaction int_act; + int_act.sa_flags = SA_RESTART; + int_act.sa_handler = int_handler; + sigemptyset(&int_act.sa_mask); +#endif + + sigaction(SIGINT, &int_act, NULL); + flags = fcntl(STDIN_FILENO, F_GETFL, 0); + flags |= FNDELAY; + fcntl(STDIN_FILENO, F_SETFL, flags); + for (i = 0; i < nloops; i++) + { + while (currPos < aloops[i].end) + { + left = aloops[i].end - currPos; + vdecodeframe(ifile, outp, order, coefTable); + writeout(stdout, left < 16 ? left : 16, outp, outp, 1); + currPos += 16; + } + + while (read(STDIN_FILENO, &cc, 1) == 0) + { + framePos = (aloops[i].start >> 4) + 1; + fseek(ifile, (framePos * 9) + soundPointer, SEEK_SET); + for (j = 0; j < 16; j++) + { + outp[j] = aloops[i].state[j]; + } + loopBegin = aloops[i].start & 0xf; + writeout(stdout, 16 - loopBegin, outp + loopBegin, outp + loopBegin, 1); + currPos = framePos * 16; + while (currPos < aloops[i].end) + { + left = aloops[i].end - currPos; + vdecodeframe(ifile, outp, order, coefTable); + writeout(stdout, left < 16 ? left : 16, outp, outp, 1); + currPos += 16; + } + } + + left = 16 - left; + if (left != 0) + { + writeout(stdout, left, &outp[left], &outp[left], 1); + } + + while (currPos < nSamples) + { + vdecodeframe(ifile, outp, order, coefTable); + left = nSamples - currPos; + writeout(stdout, left < 16 ? left : 16, outp, outp, 1); + currPos += 16; + } + + flags = fcntl(STDIN_FILENO, F_GETFL, 0); + flags &= ~FNDELAY; + fcntl(STDIN_FILENO, F_SETFL, flags); + } + } + else + { + while (currPos < nSamples) + { + vdecodeframe(ifile, outp, order, coefTable); + writeout(stdout, 16, outp, outp, 1); + currPos += 16; + } + } + + fclose(ifile); + return 0; +} diff --git a/tools/sdk-tools/adpcm/vadpcm_enc.c b/tools/sdk-tools/adpcm/vadpcm_enc.c new file mode 100644 index 00000000000..193ca641763 --- /dev/null +++ b/tools/sdk-tools/adpcm/vadpcm_enc.c @@ -0,0 +1,519 @@ +#include +#include +#include +#include +#include +#include "vadpcm.h" + +static char usage[] = "[-t -l min_loop_length] -c codebook aifcfile compressedfile"; + +int main(int argc, char **argv) +{ + s32 c; + char *progname = argv[0]; + s16 nloops = 0; + s16 numMarkers; + s16 *inBuffer; + s16 ts; + s32 minLoopLength = 800; + s32 ***coefTable = NULL; + s32 *state; + s32 order; + s32 npredictors; + s32 done = 0; + s32 truncate = 0; + s32 num; + s32 tableSize; + s32 nsam; + s32 left; + u32 newEnd; + s32 nRepeats; + s32 i; + s32 j; + s32 k; + s32 nFrames; + s32 offset; + s32 cChunkPos; + s32 currentPos; + s32 soundPointer = 0; + s32 startPointer = 0; + s32 startSoundPointer = 0; + s32 cType; + s32 nBytes = 0; + u32 loopEnd; + char *compName = "VADPCM ~4-1"; + char *appCodeName = "VADPCMCODES"; + char *appLoopName = "VADPCMLOOPS"; + u8 strnLen; + Chunk AppChunk; + Chunk FormChunk; + ChunkHeader CSndChunk; + ChunkHeader Header; + CommonChunk CommChunk; + SoundDataChunk SndDChunk; + InstrumentChunk InstChunk; + Loop *loops = NULL; + ALADPCMloop *aloops; + Marker *markers; + CodeChunk cChunk; + char filename[1024]; + FILE *fhandle; + FILE *ifile; + FILE *ofile; + + for (i = 0; i < argc; i++) { + printf("%s\n", argv[i]); + } + + if (argc < 2) + { + fprintf(stderr, "%s %s\n", progname, usage); + exit(1); + } + + while ((c = getopt(argc, argv, "tc:l:")) != -1) + { + switch (c) + { + case 'c': + if ((fhandle = fopen(optarg, "r")) == NULL) + { + fprintf(stderr, "Codebook file %s could not be opened\n", optarg); + exit(1); + } + if (readcodebook(fhandle, &coefTable, &order, &npredictors) != 0) + { + fprintf(stderr, "Error reading codebook\n"); + exit(1); + } + break; + + case 't': + truncate = 1; + break; + + case 'l': + sscanf(optarg, "%d", &minLoopLength); + break; + + default: + break; + } + } + + if (coefTable == 0) + { + fprintf(stderr, "You should specify a coefficient codebook with the [-c] option\n"); + exit(1); + } + + argv += optind - 1; + if ((ifile = fopen(argv[1], MODE_READ)) == NULL) + { + fprintf(stderr, "%s: input file [%s] could not be opened.\n", progname, argv[1]); + exit(1); + } + if ((ofile = fopen(argv[2], MODE_WRITE)) == NULL) + { + fprintf(stderr, "%s: output file [%s] could not be opened.\n", progname, argv[2]); + exit(1); + } + + state = malloc(16 * sizeof(s32)); + for (i = 0; i < 16; i++) + { + state[i] = 0; + } + +#ifndef __sgi + // If there is no instrument chunk, make sure to output zeroes instead of + // garbage. (This matches how the IRIX -g-compiled version behaves.) + memset(&InstChunk, 0, sizeof(InstChunk)); +#endif + + inBuffer = malloc(16 * sizeof(s16)); + + fread(&FormChunk, sizeof(Chunk), 1, ifile); + BSWAP32(FormChunk.ckID) + BSWAP32(FormChunk.ckSize) + BSWAP32(FormChunk.formType) + + // @bug This doesn't check for FORM for AIFF files, probably due to mistaken operator precedence. + if (!((FormChunk.ckID == 0x464f524d && // FORM + FormChunk.formType == 0x41494643) || // AIFC + FormChunk.formType == 0x41494646)) // AIFF + { + fprintf(stderr, "%s: [%s] is not an AIFF-C File\n", progname, argv[1]); + exit(1); + } + + while (!done) + { + num = fread(&Header, 8, 1, ifile); + if (num <= 0) + { + done = 1; + break; + } + BSWAP32(Header.ckID) + BSWAP32(Header.ckSize) + + Header.ckSize++, Header.ckSize &= ~1; + switch (Header.ckID) + { + case 0x434f4d4d: // COMM + offset = ftell(ifile); + num = fread(&CommChunk, sizeof(CommonChunk), 1, ifile); + if (num <= 0) + { + fprintf(stderr, "%s: error parsing file [%s]\n", progname, argv[1]); + done = 1; + } + BSWAP16(CommChunk.numChannels) + BSWAP16(CommChunk.numFramesH) + BSWAP16(CommChunk.numFramesL) + BSWAP16(CommChunk.sampleSize) + if (FormChunk.formType != 0x41494646) // AIFF + { + BSWAP16(CommChunk.compressionTypeH) + BSWAP16(CommChunk.compressionTypeL) + cType = (CommChunk.compressionTypeH << 16) + CommChunk.compressionTypeL; + if (cType != 0x4e4f4e45) // NONE + { + fprintf(stderr, "%s: file [%s] contains compressed data.\n", progname, argv[1]); + exit(1); + } + } + if (CommChunk.numChannels != 1) + { + fprintf(stderr, "%s: file [%s] contains %ld channels, only 1 channel supported.\n", progname, argv[1], (long) CommChunk.numChannels); + exit(1); + } + if (CommChunk.sampleSize != 16) + { + fprintf(stderr, "%s: file [%s] contains %ld bit samples, only 16 bit samples supported.\n", progname, argv[1], (long) CommChunk.sampleSize); + exit(1); + } + fseek(ifile, offset + Header.ckSize, SEEK_SET); + break; + + case 0x53534e44: // SSND + offset = ftell(ifile); + fread(&SndDChunk, sizeof(SoundDataChunk), 1, ifile); + BSWAP32(SndDChunk.offset) + BSWAP32(SndDChunk.blockSize) + // The assert error messages specify line numbers 219/220. Match + // that using a #line directive. +#ifdef __sgi +# line 218 +#endif + assert(SndDChunk.offset == 0); + assert(SndDChunk.blockSize == 0); + soundPointer = ftell(ifile); + fseek(ifile, offset + Header.ckSize, SEEK_SET); + break; + + case 0x4d41524b: // MARK + offset = ftell(ifile); + fread(&numMarkers, sizeof(s16), 1, ifile); + BSWAP16(numMarkers) + markers = malloc(numMarkers * sizeof(Marker)); + for (i = 0; i < numMarkers; i++) + { + fread(&markers[i], sizeof(Marker), 1, ifile); + BSWAP16(markers[i].MarkerID) + BSWAP16(markers[i].positionH) + BSWAP16(markers[i].positionL) + fread(&strnLen, 1, 1, ifile); + if ((strnLen & 1) != 0) + { + fseek(ifile, strnLen, SEEK_CUR); + } + else + { + fseek(ifile, strnLen + 1, SEEK_CUR); + } + } + fseek(ifile, offset + Header.ckSize, SEEK_SET); + break; + + case 0x494e5354: // INST + offset = ftell(ifile); + fread(&InstChunk, sizeof(InstrumentChunk), 1, ifile); + BSWAP16(InstChunk.sustainLoop.playMode) + BSWAP16(InstChunk.sustainLoop.beginLoop) + BSWAP16(InstChunk.sustainLoop.endLoop) + BSWAP16(InstChunk.releaseLoop.playMode) + BSWAP16(InstChunk.releaseLoop.beginLoop) + BSWAP16(InstChunk.releaseLoop.endLoop) + aloops = malloc(2 * sizeof(ALADPCMloop)); + loops = malloc(2 * sizeof(Loop)); + if (InstChunk.sustainLoop.playMode == 1) + { + loops[nloops].beginLoop = InstChunk.sustainLoop.beginLoop; + loops[nloops].endLoop = InstChunk.sustainLoop.endLoop; + nloops++; + } + if (InstChunk.releaseLoop.playMode == 1) + { + loops[nloops].beginLoop = InstChunk.releaseLoop.beginLoop; + loops[nloops].endLoop = InstChunk.releaseLoop.endLoop; + nloops++; + } + fseek(ifile, offset + Header.ckSize, SEEK_SET); + break; + + default: + fseek(ifile, Header.ckSize, SEEK_CUR); + break; + } + } + + FormChunk.formType = 0x41494643; // AIFC + BSWAP32(FormChunk.ckID) + BSWAP32(FormChunk.ckSize) + BSWAP32(FormChunk.formType) + fwrite(&FormChunk, sizeof(Chunk), 1, ofile); + + Header.ckID = 0x434f4d4d; // COMM + Header.ckSize = sizeof(CommonChunk) + 1 + 11; + BSWAP32(Header.ckID) + BSWAP32(Header.ckSize) + fwrite(&Header, sizeof(ChunkHeader), 1, ofile); + CommChunk.compressionTypeH = 0x4144; // AD + CommChunk.compressionTypeL = 0x5039; // P9 + cChunkPos = ftell(ofile); + // CommChunk written later + fwrite(&CommChunk, sizeof(CommonChunk), 1, ofile); + strnLen = sizeof("VADPCM ~4-1") - 1; + fwrite(&strnLen, 1, 1, ofile); + fwrite(compName, strnLen, 1, ofile); + + Header.ckID = 0x494e5354; // INST + Header.ckSize = sizeof(InstrumentChunk); + BSWAP32(Header.ckID) + BSWAP32(Header.ckSize) + fwrite(&Header, sizeof(ChunkHeader), 1, ofile); + BSWAP16(InstChunk.sustainLoop.playMode) + BSWAP16(InstChunk.sustainLoop.beginLoop) + BSWAP16(InstChunk.sustainLoop.endLoop) + BSWAP16(InstChunk.releaseLoop.playMode) + BSWAP16(InstChunk.releaseLoop.beginLoop) + BSWAP16(InstChunk.releaseLoop.endLoop) + fwrite(&InstChunk, sizeof(InstrumentChunk), 1, ofile); + + tableSize = order * 2 * npredictors * 8; + strnLen = sizeof("VADPCMCODES") - 1; + AppChunk.ckID = 0x4150504c; // APPL + AppChunk.ckSize = 4 + tableSize + 1 + strnLen + sizeof(CodeChunk); + AppChunk.formType = 0x73746f63; // stoc + BSWAP32(AppChunk.ckID) + BSWAP32(AppChunk.ckSize) + BSWAP32(AppChunk.formType) + fwrite(&AppChunk, sizeof(Chunk), 1, ofile); + cChunk.version = 1; + cChunk.order = order; + cChunk.nEntries = npredictors; + BSWAP16(cChunk.version) + BSWAP16(cChunk.order) + BSWAP16(cChunk.nEntries) + fwrite(&strnLen, 1, 1, ofile); + fwrite(appCodeName, strnLen, 1, ofile); + fwrite(&cChunk, sizeof(CodeChunk), 1, ofile); + + for (i = 0; i < npredictors; i++) + { + for (j = 0; j < order; j++) + { + for (k = 0; k < 8; k++) + { + ts = coefTable[i][k][j]; + BSWAP16(ts) + fwrite(&ts, sizeof(s16), 1, ofile); + } + } + } + + currentPos = 0; + if (soundPointer > 0) + { + fseek(ifile, soundPointer, SEEK_SET); + } + else + { + fprintf(stderr, "%s: Error in sound chunk", progname); + exit(1); + } + + soundPointer = ftell(ofile); + // CSndChunk written later + fwrite(&CSndChunk, sizeof(ChunkHeader), 1, ofile); + BSWAP32(SndDChunk.offset) + BSWAP32(SndDChunk.blockSize) + fwrite(&SndDChunk, sizeof(SoundDataChunk), 1, ofile); + startSoundPointer = ftell(ifile); + for (i = 0; i < nloops; i++) + { + if (lookupMarker(&aloops[i].start, loops[i].beginLoop, markers, numMarkers) != 0) + { + fprintf(stderr, "%s: Start loop marker not found\n", progname); + } + else if (lookupMarker(&aloops[i].end, loops[i].endLoop, markers, numMarkers) != 0) + { + fprintf(stderr, "%s: End loop marker not found\n", progname); + } + else + { + startPointer = startSoundPointer + aloops[i].start * 2; + nRepeats = 0; + newEnd = aloops[i].end; + while (newEnd - aloops[i].start < minLoopLength) + { + nRepeats++; + newEnd += aloops[i].end - aloops[i].start; + } + + while (currentPos <= aloops[i].start) + { + if (fread(inBuffer, sizeof(s16), 16, ifile) == 16) + { + BSWAP16_MANY(inBuffer, 16) + vencodeframe(ofile, inBuffer, state, coefTable, order, npredictors, 16); + currentPos += 16; + nBytes += 9; + } + else + { + fprintf(stderr, "%s: Not enough samples in file [%s]\n", progname, argv[1]); + exit(1); + } + } + + for (j = 0; j < 16; j++) + { + if (state[j] >= 0x8000) + { + state[j] = 0x7fff; + } + if (state[j] < -0x7fff) + { + state[j] = -0x7fff; + } + aloops[i].state[j] = state[j]; + } + + aloops[i].count = -1; + while (nRepeats > 0) + { + for (; currentPos + 16 < aloops[i].end; currentPos += 16) + { + if (fread(inBuffer, sizeof(s16), 16, ifile) == 16) + { + BSWAP16_MANY(inBuffer, 16) + vencodeframe(ofile, inBuffer, state, coefTable, order, npredictors, 16); + nBytes += 9; + } + } + left = aloops[i].end - currentPos; + fread(inBuffer, sizeof(s16), left, ifile); + BSWAP16_MANY(inBuffer, left) + fseek(ifile, startPointer, SEEK_SET); + fread(inBuffer + left, sizeof(s16), 16 - left, ifile); + BSWAP16_MANY(inBuffer + left, 16 - left) + vencodeframe(ofile, inBuffer, state, coefTable, order, npredictors, 16); + nBytes += 9; + currentPos = aloops[i].start - left + 16; + nRepeats--; + } + aloops[i].end = newEnd; + } + } + + nFrames = (CommChunk.numFramesH << 16) + CommChunk.numFramesL; + if ((nloops > 0U) & truncate) + { + lookupMarker(&loopEnd, loops[nloops - 1].endLoop, markers, numMarkers); + nFrames = (loopEnd + 16 < nFrames ? loopEnd + 16 : nFrames); + } + + while (currentPos < nFrames) + { + if (nFrames - currentPos < 16) + { + nsam = nFrames - currentPos; + } + else + { + nsam = 16; + } + + if (fread(inBuffer, 2, nsam, ifile) == nsam) + { + BSWAP16_MANY(inBuffer, nsam) + vencodeframe(ofile, inBuffer, state, coefTable, order, npredictors, nsam); + currentPos += nsam; + nBytes += 9; + } + else + { + fprintf(stderr, "Missed a frame!\n"); + break; + } + } + + if (nBytes % 2) + { + nBytes++; + ts = 0; + fwrite(&ts, 1, 1, ofile); + } + + if (nloops > 0) + { + strnLen = sizeof("VADPCMLOOPS") - 1; + AppChunk.ckID = 0x4150504c; // APPL + AppChunk.ckSize = nloops * sizeof(ALADPCMloop) + strnLen + 4 + 1 + 2 + 2; + AppChunk.formType = 0x73746f63; // stoc + BSWAP32(AppChunk.ckID) + BSWAP32(AppChunk.ckSize) + BSWAP32(AppChunk.formType) + fwrite(&AppChunk, sizeof(Chunk), 1, ofile); + fwrite(&strnLen, 1, 1, ofile); + fwrite(appLoopName, strnLen, 1, ofile); + ts = 1; + BSWAP16(ts) + fwrite(&ts, sizeof(s16), 1, ofile); + BSWAP16(nloops) + fwrite(&nloops, sizeof(s16), 1, ofile); + BSWAP16(nloops) + for (i = 0; i < nloops; i++) + { + BSWAP32(aloops[i].start) + BSWAP32(aloops[i].end) + BSWAP32(aloops[i].count) + BSWAP16_MANY(aloops[i].state, 16) + fwrite(&aloops[i], sizeof(ALADPCMloop), 1, ofile); + } + } + + fseek(ofile, soundPointer, SEEK_SET); + CSndChunk.ckID = 0x53534e44; // SSND + CSndChunk.ckSize = nBytes + 8; + BSWAP32(CSndChunk.ckID) + BSWAP32(CSndChunk.ckSize) + fwrite(&CSndChunk, sizeof(ChunkHeader), 1, ofile); + fseek(ofile, cChunkPos, SEEK_SET); + nFrames = nBytes * 16 / 9; + CommChunk.numFramesH = nFrames >> 16; + CommChunk.numFramesL = nFrames & 0xffff; + BSWAP16(CommChunk.numChannels) + BSWAP16(CommChunk.numFramesH) + BSWAP16(CommChunk.numFramesL) + BSWAP16(CommChunk.sampleSize) + BSWAP16(CommChunk.compressionTypeH) + BSWAP16(CommChunk.compressionTypeL) + fwrite(&CommChunk, sizeof(CommonChunk), 1, ofile); + fclose(ifile); + fclose(ofile); + return 0; +} diff --git a/tools/sdk-tools/adpcm/vdecode.c b/tools/sdk-tools/adpcm/vdecode.c new file mode 100644 index 00000000000..026dd74ccce --- /dev/null +++ b/tools/sdk-tools/adpcm/vdecode.c @@ -0,0 +1,73 @@ +#include +#include "vadpcm.h" + +void vdecodeframe(FILE *ifile, s32 *outp, s32 order, s32 ***coefTable) +{ + s32 optimalp; + s32 scale; + s32 maxlevel; + s32 i; + s32 j; + s32 in_vec[16]; + s32 ix[16]; + u8 header; + u8 c; + + maxlevel = 7; + fread(&header, 1, 1, ifile); + scale = 1 << (header >> 4); + optimalp = header & 0xf; + + for (i = 0; i < 16; i += 2) + { + fread(&c, 1, 1, ifile); + ix[i] = c >> 4; + ix[i + 1] = c & 0xf; + + if (ix[i] <= maxlevel) + { + ix[i] *= scale; + } + else + { + ix[i] = (-0x10 - -ix[i]) * scale; + } + + if (ix[i + 1] <= maxlevel) + { + ix[i + 1] *= scale; + } + else + { + ix[i + 1] = (-0x10 - -ix[i + 1]) * scale; + } + } + + for (j = 0; j < 2; j++) + { + for (i = 0; i < 8; i++) + { + in_vec[i + order] = ix[j * 8 + i]; + } + + if (j == 0) + { + for (i = 0; i < order; i++) + { + in_vec[i] = outp[16 - order + i]; + } + } + else + { + for (i = 0; i < order; i++) + { + in_vec[i] = outp[j * 8 - order + i]; + } + } + + for (i = 0; i < 8; i++) + { + outp[i + j * 8] = inner_product(order + 8, coefTable[optimalp][i], in_vec); + } + } +} diff --git a/tools/sdk-tools/adpcm/vencode.c b/tools/sdk-tools/adpcm/vencode.c new file mode 100644 index 00000000000..6d5b4ab3ac9 --- /dev/null +++ b/tools/sdk-tools/adpcm/vencode.c @@ -0,0 +1,236 @@ +#include +#include +#include +#include "vadpcm.h" + +void vencodeframe(FILE *ofile, s16 *inBuffer, s32 *state, s32 ***coefTable, s32 order, s32 npredictors, s32 nsam) +{ + s16 ix[16]; + s32 prediction[16]; + s32 inVector[16]; + s32 saveState[16]; + s32 optimalp; + s32 scale; + s32 llevel; + s32 ulevel; + s32 i; + s32 j; + s32 k; + s32 ie[16]; + s32 nIter; + s32 max; + s32 cV; + s32 maxClip; + u8 header; + u8 c; + f32 e[16]; + f32 se; + f32 min; + + // We are only given 'nsam' samples; pad with zeroes to 16. + for (i = nsam; i < 16; i++) + { + inBuffer[i] = 0; + } + + llevel = -8; + ulevel = -llevel - 1; + + // Determine the best-fitting predictor. + min = 1e30; + optimalp = 0; + for (k = 0; k < npredictors; k++) + { + // Copy over the last 'order' samples from the previous output. + for (i = 0; i < order; i++) + { + inVector[i] = state[16 - order + i]; + } + + // For 8 samples... + for (i = 0; i < 8; i++) + { + // Compute a prediction based on 'order' values from the old state, + // plus previous errors in this chunk, as an inner product with the + // coefficient table. + prediction[i] = inner_product(order + i, coefTable[k][i], inVector); + // Record the error in inVector (thus, its first 'order' samples + // will contain actual values, the rest will be error terms), and + // in floating point form in e (for no particularly good reason). + inVector[i + order] = inBuffer[i] - prediction[i]; + e[i] = (f32) inVector[i + order]; + } + + // For the next 8 samples, start with 'order' values from the end of + // the previous 8-sample chunk of inBuffer. (The code is equivalent to + // inVector[i] = inBuffer[8 - order + i].) + for (i = 0; i < order; i++) + { + inVector[i] = prediction[8 - order + i] + inVector[8 + i]; + } + + // ... and do the same thing as before to get predictions. + for (i = 0; i < 8; i++) + { + prediction[8 + i] = inner_product(order + i, coefTable[k][i], inVector); + inVector[i + order] = inBuffer[8 + i] - prediction[8 + i]; + e[8 + i] = (f32) inVector[i + order]; + } + + // Compute the L2 norm of the errors; the lowest norm decides which + // predictor to use. + se = 0.0f; + for (j = 0; j < 16; j++) + { + se += e[j] * e[j]; + } + + if (se < min) + { + min = se; + optimalp = k; + } + } + + // Do exactly the same thing again, for real. + for (i = 0; i < order; i++) + { + inVector[i] = state[16 - order + i]; + } + + for (i = 0; i < 8; i++) + { + prediction[i] = inner_product(order + i, coefTable[optimalp][i], inVector); + inVector[i + order] = inBuffer[i] - prediction[i]; + e[i] = (f32) inVector[i + order]; + } + + for (i = 0; i < order; i++) + { + inVector[i] = prediction[8 - order + i] + inVector[8 + i]; + } + + for (i = 0; i < 8; i++) + { + prediction[8 + i] = inner_product(order + i, coefTable[optimalp][i], inVector); + inVector[i + order] = inBuffer[8 + i] - prediction[8 + i]; + e[8 + i] = (f32) inVector[i + order]; + } + + // Clamp the errors to 16-bit signed ints, and put them in ie. + clamp(16, e, ie, 16); + + // Find a value with highest absolute value. + // @bug If this first finds -2^n and later 2^n, it should set 'max' to the + // latter, which needs a higher value for 'scale'. + max = 0; + for (i = 0; i < 16; i++) + { + if (fabs(ie[i]) > fabs(max)) + { + max = ie[i]; + } + } + + // Compute which power of two we need to scale down by in order to make + // all values representable as 4-bit signed integers (i.e. be in [-8, 7]). + // The worst-case 'max' is -2^15, so this will be at most 12. + for (scale = 0; scale <= 12; scale++) + { + if (max <= ulevel && max >= llevel) + { + goto out; + } + max /= 2; + } +out:; + + for (i = 0; i < 16; i++) + { + saveState[i] = state[i]; + } + + // Try with the computed scale, but if it turns out we don't fit in 4 bits + // (if some |cV| >= 2), use scale + 1 instead (i.e. downscaling by another + // factor of 2). + scale--; + nIter = 0; + do + { + nIter++; + maxClip = 0; + scale++; + if (scale > 12) + { + scale = 12; + } + + // Copy over the last 'order' samples from the previous output. + for (i = 0; i < order; i++) + { + inVector[i] = saveState[16 - order + i]; + } + + // For 8 samples... + for (i = 0; i < 8; i++) + { + // Compute a prediction based on 'order' values from the old state, + // plus previous *quantized* errors in this chunk (because that's + // all the decoder will have available). + prediction[i] = inner_product(order + i, coefTable[optimalp][i], inVector); + + // Compute the error, and divide it by 2^scale, rounding to the + // nearest integer. This should ideally result in a 4-bit integer. + se = (f32) inBuffer[i] - (f32) prediction[i]; + ix[i] = qsample(se, 1 << scale); + + // Clamp the error to a 4-bit signed integer, and record what delta + // was needed for that. + cV = (s16) clip(ix[i], llevel, ulevel) - ix[i]; + if (maxClip < abs(cV)) + { + maxClip = abs(cV); + } + ix[i] += cV; + + // Record the quantized error in inVector for later predictions, + // and the quantized (decoded) output in state (for use in the next + // batch of 8 samples). + inVector[i + order] = ix[i] * (1 << scale); + state[i] = prediction[i] + inVector[i + order]; + } + + // Copy over the last 'order' decoded samples from the above chunk. + for (i = 0; i < order; i++) + { + inVector[i] = state[8 - order + i]; + } + + // ... and do the same thing as before. + for (i = 0; i < 8; i++) + { + prediction[8 + i] = inner_product(order + i, coefTable[optimalp][i], inVector); + se = (f32) inBuffer[8 + i] - (f32) prediction[8 + i]; + ix[8 + i] = qsample(se, 1 << scale); + cV = (s16) clip(ix[8 + i], llevel, ulevel) - ix[8 + i]; + if (maxClip < abs(cV)) + { + maxClip = abs(cV); + } + ix[8 + i] += cV; + inVector[i + order] = ix[8 + i] * (1 << scale); + state[8 + i] = prediction[8 + i] + inVector[i + order]; + } + } + while (maxClip >= 2 && nIter < 2); + + // The scale, the predictor index, and the 16 computed outputs are now all + // 4-bit numbers. Write them out as 1 + 8 bytes. + header = (scale << 4) | (optimalp & 0xf); + fwrite(&header, 1, 1, ofile); + for (i = 0; i < 16; i += 2) + { + c = (ix[i] << 4) | (ix[i + 1] & 0xf); + fwrite(&c, 1, 1, ofile); + } +} diff --git a/tools/sdk-tools/adpcm/vpredictor.c b/tools/sdk-tools/adpcm/vpredictor.c new file mode 100644 index 00000000000..3c35e2fcb2e --- /dev/null +++ b/tools/sdk-tools/adpcm/vpredictor.c @@ -0,0 +1,141 @@ +#include +#include +#include "vadpcm.h" + +s32 readcodebook(FILE *fhandle, s32 ****table, s32 *order, s32 *npredictors) +{ + s32 **table_entry; + s32 i; + s32 j; + s32 k; + + fscanf(fhandle, "%d", order); + fscanf(fhandle, "%d", npredictors); + *table = malloc(*npredictors * sizeof(s32 **)); + for (i = 0; i < *npredictors; i++) + { + (*table)[i] = malloc(8 * sizeof(s32 *)); + for (j = 0; j < 8; j++) + { + (*table)[i][j] = malloc((*order + 8) * sizeof(s32)); + } + } + + for (i = 0; i < *npredictors; i++) + { + table_entry = (*table)[i]; + for (j = 0; j < *order; j++) + { + for (k = 0; k < 8; k++) + { + fscanf(fhandle, "%d", &table_entry[k][j]); + } + } + + for (k = 1; k < 8; k++) + { + table_entry[k][*order] = table_entry[k - 1][*order - 1]; + } + + table_entry[0][*order] = 1 << 11; + + for (k = 1; k < 8; k++) + { + for (j = 0; j < k; j++) + { + table_entry[j][k + *order] = 0; + } + + for (; j < 8; j++) + { + table_entry[j][k + *order] = table_entry[j - k][*order]; + } + } + } + return 0; +} + +s32 readaifccodebook(FILE *fhandle, s32 ****table, s16 *order, s16 *npredictors) +{ + s32 **table_entry; + s32 i; + s32 j; + s32 k; + s16 ts; + + fread(order, sizeof(s16), 1, fhandle); + BSWAP16(*order) + fread(npredictors, sizeof(s16), 1, fhandle); + BSWAP16(*npredictors) + *table = malloc(*npredictors * sizeof(s32 **)); + for (i = 0; i < *npredictors; i++) + { + (*table)[i] = malloc(8 * sizeof(s32 *)); + for (j = 0; j < 8; j++) + { + (*table)[i][j] = malloc((*order + 8) * sizeof(s32)); + } + } + + for (i = 0; i < *npredictors; i++) + { + table_entry = (*table)[i]; + for (j = 0; j < *order; j++) + { + for (k = 0; k < 8; k++) + { + fread(&ts, sizeof(s16), 1, fhandle); + BSWAP16(ts) + table_entry[k][j] = ts; + } + } + + for (k = 1; k < 8; k++) + { + table_entry[k][*order] = table_entry[k - 1][*order - 1]; + } + + table_entry[0][*order] = 1 << 11; + + for (k = 1; k < 8; k++) + { + for (j = 0; j < k; j++) + { + table_entry[j][k + *order] = 0; + } + + for (; j < 8; j++) + { + table_entry[j][k + *order] = table_entry[j - k][*order]; + } + } + } + return 0; +} + +s32 inner_product(s32 length, s32 *v1, s32 *v2) +{ + s32 j; + s32 dout; + s32 fiout; + s32 out; + + j = 0; + out = 0; + for (; j < length; j++) + { + out += *v1++ * *v2++; + } + + // Compute "out / 2^11", rounded down. + dout = out / (1 << 11); + fiout = dout * (1 << 11); + if (out - fiout < 0) + { + return dout - 1; + } + else + { + return dout; + } +} diff --git a/tools/sdk-tools/tabledesign/.gitignore b/tools/sdk-tools/tabledesign/.gitignore new file mode 100644 index 00000000000..04bd42542d9 --- /dev/null +++ b/tools/sdk-tools/tabledesign/.gitignore @@ -0,0 +1,9 @@ +*.o +*.s +*.dump +*.aiff +*.aifc +*.table +/tabledesign_irix +/tabledesign_native +/tabledesign_orig diff --git a/tools/sdk-tools/tabledesign/Makefile b/tools/sdk-tools/tabledesign/Makefile new file mode 100644 index 00000000000..a06d70af3e4 --- /dev/null +++ b/tools/sdk-tools/tabledesign/Makefile @@ -0,0 +1,31 @@ +# Makefile for building tabledesign for either IRIX or natively. +# For an IRIX build, the env variable IRIX_ROOT should point to the root of an +# IRIX filesystem, and QEMU_IRIX should point to the qemu-irix binary. + +IRIX_CC := $(QEMU_IRIX) -silent -L $(IRIX_ROOT) $(IRIX_ROOT)/usr/bin/cc +IRIX_CFLAGS := -fullwarn -Wab,-r4300_mul -Xcpluscomm -mips1 -O2 + +NATIVE_CC := gcc +NATIVE_CFLAGS := -Wall -Wno-uninitialized -O2 + +LDFLAGS := -lm -laudiofile + +default: native +all: irix native + +irix: tabledesign_irix +native: tabledesign_native + +clean: + $(RM) *.o tabledesign_irix tabledesign_native + +%.o: %.c + $(IRIX_CC) -c $(IRIX_CFLAGS) $< -o $@ + +tabledesign_irix: tabledesign.o codebook.o estimate.o print.o + $(IRIX_CC) $^ -o $@ $(LDFLAGS) + +tabledesign_native: tabledesign.c codebook.c estimate.c print.c + $(NATIVE_CC) $(NATIVE_CFLAGS) $^ -o $@ $(LDFLAGS) + +.PHONY: default all irix native clean diff --git a/tools/sdk-tools/tabledesign/codebook.c b/tools/sdk-tools/tabledesign/codebook.c new file mode 100644 index 00000000000..579a1683cfa --- /dev/null +++ b/tools/sdk-tools/tabledesign/codebook.c @@ -0,0 +1,104 @@ +#include +#include "tabledesign.h" + +void split(double **table, double *delta, int order, int npredictors, double scale) +{ + int i, j; + + for (i = 0; i < npredictors; i++) + { + for (j = 0; j <= order; j++) + { + table[i + npredictors][j] = table[i][j] + delta[j] * scale; + } + } +} + +void refine(double **table, int order, int npredictors, double **data, int dataSize, int refineIters, UNUSED double unused) +{ + int iter; // spD8 + double **rsums; + int *counts; // spD0 + double *temp_s7; + double dist; + double dummy; // spC0 + double bestValue; + int bestIndex; + int i, j; + + rsums = malloc(npredictors * sizeof(double*)); + for (i = 0; i < npredictors; i++) + { + rsums[i] = malloc((order + 1) * sizeof(double)); + } + + counts = malloc(npredictors * sizeof(int)); + temp_s7 = malloc((order + 1) * sizeof(double)); + + for (iter = 0; iter < refineIters; iter++) + { + for (i = 0; i < npredictors; i++) + { + counts[i] = 0; + for (j = 0; j <= order; j++) + { + rsums[i][j] = 0.0; + } + } + + for (i = 0; i < dataSize; i++) + { + bestValue = 1e30; + bestIndex = 0; + + for (j = 0; j < npredictors; j++) + { + dist = model_dist(table[j], data[i], order); + if (dist < bestValue) + { + bestValue = dist; + bestIndex = j; + } + } + + counts[bestIndex]++; + rfroma(data[i], order, temp_s7); + for (j = 0; j <= order; j++) + { + rsums[bestIndex][j] += temp_s7[j]; + } + } + + for (i = 0; i < npredictors; i++) + { + if (counts[i] > 0) + { + for (j = 0; j <= order; j++) + { + rsums[i][j] /= counts[i]; + } + } + } + + for (i = 0; i < npredictors; i++) + { + durbin(rsums[i], order, temp_s7, table[i], &dummy); + + for (j = 1; j <= order; j++) + { + if (temp_s7[j] >= 1.0) temp_s7[j] = 0.9999999999; + if (temp_s7[j] <= -1.0) temp_s7[j] = -0.9999999999; + } + + afromk(temp_s7, table[i], order); + } + } + + free(counts); + for (i = 0; i < npredictors; i++) + { + free(rsums[i]); + } + free(rsums); + free(temp_s7); +} diff --git a/tools/sdk-tools/tabledesign/estimate.c b/tools/sdk-tools/tabledesign/estimate.c new file mode 100644 index 00000000000..da2b4e88bc0 --- /dev/null +++ b/tools/sdk-tools/tabledesign/estimate.c @@ -0,0 +1,342 @@ +#include +#include +#include "tabledesign.h" + +/** + * Computes the autocorrelation of a vector. More precisely, it computes the + * dot products of vec[i:] and vec[:-i] for i in [0, k). Unused. + * + * See https://en.wikipedia.org/wiki/Autocorrelation. + */ +void acf(double *vec, int n, double *out, int k) +{ + int i, j; + double sum; + for (i = 0; i < k; i++) + { + sum = 0.0; + for (j = 0; j < n - i; j++) + { + sum += vec[j + i] * vec[j]; + } + out[i] = sum; + } +} + +// https://en.wikipedia.org/wiki/Durbin%E2%80%93Watson_statistic ? +// "detects the presence of autocorrelation at lag 1 in the residuals (prediction errors)" +int durbin(double *arg0, int n, double *arg2, double *arg3, double *outSomething) +{ + int i, j; + double sum, div; + int ret; + + arg3[0] = 1.0; + div = arg0[0]; + ret = 0; + + for (i = 1; i <= n; i++) + { + sum = 0.0; + for (j = 1; j <= i-1; j++) + { + sum += arg3[j] * arg0[i - j]; + } + + arg3[i] = (div > 0.0 ? -(arg0[i] + sum) / div : 0.0); + arg2[i] = arg3[i]; + + if (fabs(arg2[i]) > 1.0) + { + ret++; + } + + for (j = 1; j < i; j++) + { + arg3[j] += arg3[i - j] * arg3[i]; + } + + div *= 1.0 - arg3[i] * arg3[i]; + } + *outSomething = div; + return ret; +} + +void afromk(double *in, double *out, int n) +{ + int i, j; + out[0] = 1.0; + for (i = 1; i <= n; i++) + { + out[i] = in[i]; + for (j = 1; j <= i - 1; j++) + { + out[j] += out[i - j] * out[i]; + } + } +} + +int kfroma(double *in, double *out, int n) +{ + int i, j; + double div; + double temp; + double *next; + int ret; + + ret = 0; + next = malloc((n + 1) * sizeof(double)); + + out[n] = in[n]; + for (i = n - 1; i >= 1; i--) + { + for (j = 0; j <= i; j++) + { + temp = out[i + 1]; + div = 1.0 - (temp * temp); + if (div == 0.0) + { + free(next); + return 1; + } + next[j] = (in[j] - in[i + 1 - j] * temp) / div; + } + + for (j = 0; j <= i; j++) + { + in[j] = next[j]; + } + + out[i] = next[i]; + if (fabs(out[i]) > 1.0) + { + ret++; + } + } + + free(next); + return ret; +} + +void rfroma(double *arg0, int n, double *arg2) +{ + int i, j; + double **mat; + double div; + + mat = malloc((n + 1) * sizeof(double*)); + mat[n] = malloc((n + 1) * sizeof(double)); + mat[n][0] = 1.0; + for (i = 1; i <= n; i++) + { + mat[n][i] = -arg0[i]; + } + + for (i = n; i >= 1; i--) + { + mat[i - 1] = malloc(i * sizeof(double)); + div = 1.0 - mat[i][i] * mat[i][i]; + for (j = 1; j <= i - 1; j++) + { + mat[i - 1][j] = (mat[i][i - j] * mat[i][i] + mat[i][j]) / div; + } + } + + arg2[0] = 1.0; + for (i = 1; i <= n; i++) + { + arg2[i] = 0.0; + for (j = 1; j <= i; j++) + { + arg2[i] += mat[i][j] * arg2[i - j]; + } + } + + free(mat[n]); + for (i = n; i > 0; i--) + { + free(mat[i - 1]); + } + free(mat); +} + +double model_dist(double *arg0, double *arg1, int n) +{ + double *sp3C; + double *sp38; + double ret; + int i, j; + + sp3C = malloc((n + 1) * sizeof(double)); + sp38 = malloc((n + 1) * sizeof(double)); + rfroma(arg1, n, sp3C); + + for (i = 0; i <= n; i++) + { + sp38[i] = 0.0; + for (j = 0; j <= n - i; j++) + { + sp38[i] += arg0[j] * arg0[i + j]; + } + } + + ret = sp38[0] * sp3C[0]; + for (i = 1; i <= n; i++) + { + ret += 2 * sp3C[i] * sp38[i]; + } + + free(sp3C); + free(sp38); + return ret; +} + +// compute autocorrelation matrix? +void acmat(short *in, int n, int m, double **out) +{ + int i, j, k; + for (i = 1; i <= n; i++) + { + for (j = 1; j <= n; j++) + { + out[i][j] = 0.0; + for (k = 0; k < m; k++) + { + out[i][j] += in[k - i] * in[k - j]; + } + } + } +} + +// compute autocorrelation vector? +void acvect(short *in, int n, int m, double *out) +{ + int i, j; + for (i = 0; i <= n; i++) + { + out[i] = 0.0; + for (j = 0; j < m; j++) + { + out[i] -= in[j - i] * in[j]; + } + } +} + +/** + * Replaces a real n-by-n matrix "a" with the LU decomposition of a row-wise + * permutation of itself. + * + * Input parameters: + * a: The matrix which is operated on. 1-indexed; it should be of size + * (n+1) x (n+1), and row/column index 0 is not used. + * n: The size of the matrix. + * + * Output parameters: + * indx: The row permutation performed. 1-indexed; it should be of size n+1, + * and index 0 is not used. + * d: the determinant of the permutation matrix. + * + * Returns 1 to indicate failure if the matrix is singular or has zeroes on the + * diagonal, 0 on success. + * + * Derived from ludcmp in "Numerical Recipes in C: The Art of Scientific Computing", + * with modified error handling. + */ +int lud(double **a, int n, int *indx, int *d) +{ + int i,imax,j,k; + double big,dum,sum,temp; + double min,max; + double *vv; + + vv = malloc((n + 1) * sizeof(double)); + *d=1; + for (i=1;i<=n;i++) { + big=0.0; + for (j=1;j<=n;j++) + if ((temp=fabs(a[i][j])) > big) big=temp; + if (big == 0.0) return 1; + vv[i]=1.0/big; + } + for (j=1;j<=n;j++) { + for (i=1;i= big) { + big=dum; + imax=i; + } + } + if (j != imax) { + for (k=1;k<=n;k++) { + dum=a[imax][k]; + a[imax][k]=a[j][k]; + a[j][k]=dum; + } + *d = -(*d); + vv[imax]=vv[j]; + } + indx[j]=imax; + if (a[j][j] == 0.0) return 1; + if (j != n) { + dum=1.0/(a[j][j]); + for (i=j+1;i<=n;i++) a[i][j] *= dum; + } + } + free(vv); + + min = 1e10; + max = 0.0; + for (i = 1; i <= n; i++) + { + temp = fabs(a[i][i]); + if (temp < min) min = temp; + if (temp > max) max = temp; + } + return min / max < 1e-10 ? 1 : 0; +} + +/** + * Solves the set of n linear equations Ax = b, using LU decomposition + * back-substitution. + * + * Input parameters: + * a: The LU decomposition of a matrix, created by "lud". + * n: The size of the matrix. + * indx: Row permutation vector, created by "lud". + * b: The vector b in the equation. 1-indexed; is should be of size n+1, and + * index 0 is not used. + * + * Output parameters: + * b: The output vector x. 1-indexed. + * + * From "Numerical Recipes in C: The Art of Scientific Computing". + */ +void lubksb(double **a, int n, int *indx, double *b) +{ + int i,ii=0,ip,j; + double sum; + + for (i=1;i<=n;i++) { + ip=indx[i]; + sum=b[ip]; + b[ip]=b[i]; + if (ii) + for (j=ii;j<=i-1;j++) sum -= a[i][j]*b[j]; + else if (sum) ii=i; + b[i]=sum; + } + for (i=n;i>=1;i--) { + sum=b[i]; + for (j=i+1;j<=n;j++) sum -= a[i][j]*b[j]; + b[i]=sum/a[i][i]; + } +} diff --git a/tools/sdk-tools/tabledesign/print.c b/tools/sdk-tools/tabledesign/print.c new file mode 100644 index 00000000000..80fe9e08465 --- /dev/null +++ b/tools/sdk-tools/tabledesign/print.c @@ -0,0 +1,89 @@ +#include +#include +#include "tabledesign.h" + +int print_entry(FILE *out, double *row, int order) +{ + double **table; + double fval; + int ival; + int i, j, k; + int overflows; + + table = malloc(8 * sizeof(double*)); + + for (i = 0; i < 8; i++) + { + table[i] = malloc(order * sizeof(double)); + } + + for (i = 0; i < order; i++) + { + for (j = 0; j < i; j++) + { + table[i][j] = 0.0; + } + + for (j = i; j < order; j++) + { + table[i][j] = -row[order - j + i]; + } + } + + for (i = order; i < 8; i++) + { + for (j = 0; j < order; j++) + { + table[i][j] = 0.0; + } + } + + for (i = 1; i < 8; i++) + { + for (j = 1; j <= order; j++) + { + if (i - j >= 0) + { + for (k = 0; k < order; k++) + { + table[i][k] -= row[j] * table[i - j][k]; + } + } + } + } + + overflows = 0; + for (i = 0; i < order; i++) + { + for (j = 0; j < 8; j++) + { + fval = table[j][i] * 2048.0; + if (fval < 0.0) + { + ival = (int) (fval - 0.5); + if (ival < -0x8000) + { + overflows++; + } + } + else + { + ival = (int) (fval + 0.5); + if (ival >= 0x8000) + { + overflows++; + } + } + fprintf(out, "%5d ", ival); + } + + fprintf(out, "\n"); + } + + for (i = 0; i < 8; i++) + { + free(table[i]); + } + free(table); + return overflows; +} diff --git a/tools/sdk-tools/tabledesign/tabledesign.c b/tools/sdk-tools/tabledesign/tabledesign.c new file mode 100644 index 00000000000..f85757c42e0 --- /dev/null +++ b/tools/sdk-tools/tabledesign/tabledesign.c @@ -0,0 +1,262 @@ +#include +#include +#include +#include +#include +#include "tabledesign.h" + +#ifdef __sgi + +typedef long SampleFormat; + +#define MODE_READ "r" + +#else + +// The modern implementation of SGI's audiofile library which is in Ubuntu +// (https://github.com/mpruett/audiofile/) has renamed some of the functions, +// and changed some data types. + +typedef int SampleFormat; +#define AFopenfile afOpenFile +#define AFgetchannels afGetChannels +#define AFgettrackids afGetTrackIDs +#define AFgetsampfmt afGetSampleFormat +#define AFgetframecnt afGetFrameCount +#define AFgetrate afGetRate +#define AFreadframes afReadFrames + +#define MODE_READ "rb" + +#endif + +char usage[80] = "[-o order -s bits -t thresh -i refine_iter -f frame_size] aifcfile"; + +int main(int argc, char **argv) +{ + const char *programName; // sp118 + double thresh; // sp110 + int order; // sp10C + int bits; // sp108 + int refineIters; // sp104 + int frameSize; // sp100 + UNUSED int rate; + int frameCount; + int opt; + double *spF4; + double dummy; // spE8 + double **mat; // spE4 + double **data; // spD0 + double *splitDelta; // spCC + int j; // spC0 + int permDet; + int curBits; // spB8 + int npredictors; // spB4 + int *perm; // spB0 + int numOverflows; // spAC + SampleFormat sampleFormat; // sp90 + SampleFormat sampleWidth; // sp8C + AFfilehandle afFile; // sp88 + int channels; + int tracks; + double *vec; // s2 + double **temp_s1; + short *temp_s3; + int i; + int dataSize; // s4 + + order = 2; + bits = 2; + refineIters = 2; + frameSize = 16; + numOverflows = 0; + programName = argv[0]; + thresh = 10.0; + + if (argc < 2) + { + fprintf(stderr, "%s %s\n", argv[0], usage); + exit(1); + } + + while ((opt = getopt(argc, argv, "o:s:t:i:f:")) != -1) + { + switch (opt) + { + case 'o': + if (sscanf(optarg, "%d", &order) != 1) + order = 2; + break; + case 's': + if (sscanf(optarg, "%d", &bits) != 1) + bits = 2; + break; + case 'f': + if (sscanf(optarg, "%d", &frameSize) != 1) + frameSize = 16; + break; + case 'i': + if (sscanf(optarg, "%d", &refineIters) != 1) + refineIters = 2; + break; + case 't': + if (sscanf(optarg, "%lf", &thresh) != 1) + thresh = 10.0; + break; + } + } + + argv = &argv[optind - 1]; + + afFile = AFopenfile(argv[1], MODE_READ, NULL); + if (afFile == NULL) + { + fprintf(stderr, + "%s: input AIFC file [%s] could not be opened.\n", + programName, argv[1]); + exit(1); + } + + channels = AFgetchannels(afFile, AF_DEFAULT_TRACK); + if (channels != 1) + { + fprintf(stderr, + "%s: file [%s] contains %d channels, only 1 channel supported.\n", + programName, argv[1], channels); + exit(1); + } + + tracks = AFgettrackids(afFile, NULL); + if (tracks != 1) + { + fprintf(stderr, + "%s: file [%s] contains %d tracks, only 1 track supported.\n", + programName, argv[1], tracks); + exit(1); + } + + AFgetsampfmt(afFile, AF_DEFAULT_TRACK, &sampleFormat, &sampleWidth); + if (sampleWidth != 16) + { + fprintf(stderr, + "%s: file [%s] contains %d bit samples, only 16 bit samples supported.\n", + programName, argv[1], (int)sampleWidth); + exit(1); + } + + temp_s1 = malloc((1 << bits) * sizeof(double*)); + for (i = 0; i < (1 << bits); i++) + { + temp_s1[i] = malloc((order + 1) * sizeof(double)); + } + + splitDelta = malloc((order + 1) * sizeof(double)); + temp_s3 = malloc(frameSize * 2 * sizeof(short)); + for (i = 0; i < frameSize * 2; i++) + { + temp_s3[i] = 0; + } + + vec = malloc((order + 1) * sizeof(double)); + spF4 = malloc((order + 1) * sizeof(double)); + mat = malloc((order + 1) * sizeof(double*)); + for (i = 0; i <= order; i++) + { + mat[i] = malloc((order + 1) * sizeof(double)); + } + + perm = malloc((order + 1) * sizeof(int)); + frameCount = AFgetframecnt(afFile, AF_DEFAULT_TRACK); + rate = AFgetrate(afFile, AF_DEFAULT_TRACK); + data = malloc(frameCount * sizeof(double*)); + dataSize = 0; + + while (AFreadframes(afFile, AF_DEFAULT_TRACK, temp_s3 + frameSize, frameSize) == frameSize) + { + acvect(temp_s3 + frameSize, order, frameSize, vec); + if (fabs(vec[0]) > thresh) + { + acmat(temp_s3 + frameSize, order, frameSize, mat); + if (lud(mat, order, perm, &permDet) == 0) + { + lubksb(mat, order, perm, vec); + vec[0] = 1.0; + if (kfroma(vec, spF4, order) == 0) + { + data[dataSize] = malloc((order + 1) * sizeof(double)); + data[dataSize][0] = 1.0; + + for (i = 1; i <= order; i++) + { + if (spF4[i] >= 1.0) spF4[i] = 0.9999999999; + if (spF4[i] <= -1.0) spF4[i] = -0.9999999999; + } + + afromk(spF4, data[dataSize], order); + dataSize++; + } + } + } + + for (i = 0; i < frameSize; i++) + { + temp_s3[i] = temp_s3[i + frameSize]; + } + } + + vec[0] = 1.0; + for (j = 1; j <= order; j++) + { + vec[j] = 0.0; + } + + for (i = 0; i < dataSize; i++) + { + rfroma(data[i], order, temp_s1[0]); + for (j = 1; j <= order; j++) + { + vec[j] += temp_s1[0][j]; + } + } + + for (j = 1; j <= order; j++) + { + vec[j] /= dataSize; + } + + durbin(vec, order, spF4, temp_s1[0], &dummy); + + for (j = 1; j <= order; j++) + { + if (spF4[j] >= 1.0) spF4[j] = 0.9999999999; + if (spF4[j] <= -1.0) spF4[j] = -0.9999999999; + } + + afromk(spF4, temp_s1[0], order); + curBits = 0; + while (curBits < bits) + { + for (i = 0; i <= order; i++) + { + splitDelta[i] = 0.0; + } + splitDelta[order - 1] = -1.0; + split(temp_s1, splitDelta, order, 1 << curBits, 0.01); + curBits++; + refine(temp_s1, order, 1 << curBits, data, dataSize, refineIters, 0.0); + } + + npredictors = 1 << curBits; + fprintf(stdout, "%d\n%d\n", order, npredictors); + + for (i = 0; i < npredictors; i++) + { + numOverflows += print_entry(stdout, temp_s1[i], order); + } + + if (numOverflows > 0) + { + fprintf(stderr, "There was overflow - check the table\n"); + } + return 0; +} diff --git a/tools/sdk-tools/tabledesign/tabledesign.h b/tools/sdk-tools/tabledesign/tabledesign.h new file mode 100644 index 00000000000..89c7a154a41 --- /dev/null +++ b/tools/sdk-tools/tabledesign/tabledesign.h @@ -0,0 +1,30 @@ +#ifndef TABLEDESIGN_H +#define TABLEDESIGN_H + +#include + +#ifdef __GNUC__ +#define UNUSED __attribute__((unused)) +#else +#define UNUSED +#endif + +// estimate.c +int durbin(double *thing, int n, double *thing2, double *thing3, double *outSomething); +void afromk(double *in, double *out, int n); +int kfroma(double *in, double *out, int n); +void rfroma(double *dataRow, int n, double *thing3); +double model_dist(double *first, double *second, int n); +void acmat(short *in, int n, int m, double **mat); +void acvect(short *in, int n, int m, double *vec); +int lud(double **a, int n, int *indx, int *d); +void lubksb(double **a, int n, int *indx, double *b); + +// codebook.c +void split(double **table, double *delta, int order, int npredictors, double scale); +void refine(double **table, int order, int npredictors, double **data, int dataSize, int refineIters, double unused); + +// print.c +int print_entry(FILE *out, double *row, int order); + +#endif