Created
November 5, 2018 21:40
-
-
Save ShinyDragonHunter/b65599431adfaefead614763bf1b9f92 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
.include "asm/macros.inc" | |
.include "constants/gba_constants.inc" | |
.include "constants/m4a_constants.inc" | |
.syntax unified | |
.text | |
thumb_func_start umul3232H32 | |
umul3232H32: | |
adr r2, __umul3232H32 | |
bx r2 | |
.arm | |
__umul3232H32: | |
umull r2, r3, r0, r1 | |
add r0, r3, 0 | |
bx lr | |
thumb_func_end umul3232H32 | |
thumb_func_start SoundMain | |
SoundMain: | |
ldr r0, lt_SOUND_INFO_PTR | |
ldr r0, [r0] | |
ldr r2, lt_ID_NUMBER | |
ldr r3, [r0, o_SoundInfo_ident] | |
cmp r2, r3 | |
beq SoundMain_1 | |
bx lr @ Exit the function if ident doesn't match ID_NUMBER. | |
SoundMain_1: | |
adds r3, 1 | |
str r3, [r0, o_SoundInfo_ident] | |
push {r4-r7,lr} | |
mov r1, r8 | |
mov r2, r9 | |
mov r3, r10 | |
mov r4, r11 | |
push {r0-r4} | |
sub sp, 0x18 | |
ldrb r1, [r0, o_SoundInfo_maxLines] | |
cmp r1, 0 @ if maxLines is 0, there is no maximum | |
beq SoundMain_3 | |
ldr r2, lt_REG_VCOUNT | |
ldrb r2, [r2] | |
cmp r2, VCOUNT_VBLANK | |
bhs SoundMain_2 | |
adds r2, TOTAL_SCANLINES | |
SoundMain_2: | |
adds r1, r2 | |
SoundMain_3: | |
str r1, [sp, 0x14] | |
ldr r3, [r0, o_SoundInfo_func] | |
cmp r3, 0 | |
beq SoundMain_4 | |
ldr r0, [r0, o_SoundInfo_intp] | |
bl call_r3 | |
ldr r0, [sp, 0x18] | |
SoundMain_4: | |
ldr r3, [r0, o_SoundInfo_CgbSound] | |
bl call_r3 | |
ldr r0, [sp, 0x18] | |
ldr r3, [r0, o_SoundInfo_pcmSamplesPerVBlank] | |
mov r8, r3 | |
ldr r5, lt_o_SoundInfo_pcmBuffer | |
adds r5, r0 | |
ldrb r4, [r0, o_SoundInfo_pcmDmaCounter] | |
subs r7, r4, 1 | |
bls SoundMain_5 | |
ldrb r1, [r0, o_SoundInfo_pcmDmaPeriod] | |
subs r1, r7 | |
mov r2, r8 | |
muls r2, r1 | |
adds r5, r2 | |
SoundMain_5: | |
str r5, [sp, 0x8] | |
ldr r6, lt_PCM_DMA_BUF_SIZE | |
ldr r3, lt_SoundMainRAM_Buffer | |
bx r3 | |
.align 2, 0 | |
lt_SOUND_INFO_PTR: .word SOUND_INFO_PTR | |
lt_ID_NUMBER: .word ID_NUMBER | |
lt_SoundMainRAM_Buffer: .word SoundMainRAM_Buffer + 1 | |
lt_REG_VCOUNT: .word REG_VCOUNT | |
lt_o_SoundInfo_pcmBuffer: .word o_SoundInfo_pcmBuffer | |
lt_PCM_DMA_BUF_SIZE: .word PCM_DMA_BUF_SIZE | |
thumb_func_end SoundMain | |
.equ POKE_INIT, 1 | |
.equ DMA_FIX, 0 | |
.equ ENABLE_DECOMPRESSION, 1 | |
/* stack variables */ | |
.equ ARG_FRAME_LENGTH, 0x0 @ TODO actually use this variable | |
.equ ARG_REMAIN_CHN, 0x4 @ This is the channel count variable | |
.equ ARG_BUFFER_POS, 0x8 @ stores the current output buffer pointer | |
.equ ARG_LOOP_START_POS, 0xC @ stores wave loop start position in channel loop | |
.equ ARG_LOOP_LENGTH, 0x10 @ '' '' '' end position | |
.equ ARG_BUFFER_POS_INDEX_HINT, 0x14 | |
.equ ARG_PCM_STRUCT, 0x18 @ pointer to engine the main work area | |
/* channel struct */ | |
.equ CHN_STATUS, 0x0 @ [byte] channel status bitfield | |
.equ CHN_MODE, 0x1 @ [byte] channel mode bitfield | |
.equ CHN_VOL_1, 0x2 @ [byte] volume right | |
.equ CHN_VOL_2, 0x3 @ [byte] volume left | |
.equ CHN_ATTACK, 0x4 @ [byte] wave attack summand | |
.equ CHN_DECAY, 0x5 @ [byte] wave decay factor | |
.equ CHN_SUSTAIN, 0x6 @ [byte] wave sustain level | |
.equ CHN_RELEASE, 0x7 @ [byte] wave release factor | |
.equ CHN_ADSR_LEVEL, 0x9 @ [byte] current envelope level | |
.equ CHN_FINAL_VOL_1, 0xA @ [byte] not used anymore! | |
.equ CHN_FINAL_VOL_2, 0xB @ [byte] not used anymore! | |
.equ CHN_ECHO_VOL, 0xC @ [byte] pseudo echo volume | |
.equ CHN_ECHO_REMAIN, 0xD @ [byte] pseudo echo length | |
.equ CHN_SAMPLE_COUNTDOWN, 0x18 @ [word] sample countdown in mixing loop | |
.equ CHN_FINE_POSITION, 0x1C @ [word] inter sample position (23 bits) | |
.equ CHN_FREQUENCY, 0x20 @ [word] sample rate (in Hz) | |
.equ CHN_WAVE_OFFSET, 0x24 @ [word] wave header pointer | |
.equ CHN_POSITION_ABS, 0x28 @ [word] points to the current position in the wave data (relative offset for compressed samples) | |
.equ CHN_BLOCK_COUNT, 0x3C @ [word] only used for compressed samples: contains the value of the block that is currently decoded | |
/* wave header struct */ | |
.equ WAVE_LOOP_FLAG, 0x3 @ [byte] 0x0 = oneshot; 0x40 = looped | |
.equ WAVE_FREQ, 0x4 @ [word] pitch adjustment value = mid-C samplerate * 1024 | |
.equ WAVE_LOOP_START, 0x8 @ [word] loop start position | |
.equ WAVE_LENGTH, 0xC @ [word] loop end / wave end position | |
.equ WAVE_DATA, 0x10 @ [byte array] actual wave data | |
/* pulse wave synth configuration offset */ | |
.equ SYNTH_BASE_WAVE_DUTY, 0x1 @ [byte] | |
.equ SYNTH_WIDTH_CHANGE_1, 0x2 @ [byte] | |
.equ SYNTH_MOD_AMOUNT, 0x3 @ [byte] | |
.equ SYNTH_WIDTH_CHANGE_2, 0x4 @ [byte] | |
/* CHN_STATUS flags - 0x0 = OFF */ | |
.equ FLAG_CHN_INIT, 0x80 @ [bit] write this value to init a channel | |
.equ FLAG_CHN_RELEASE, 0x40 @ [bit] write this value to release (fade out) the channel | |
.equ FLAG_CHN_COMP, 0x20 @ [bit] is wave being played compressed (yes/no) | |
.equ FLAG_CHN_LOOP, 0x10 @ [bit] loop (yes/no) | |
.equ FLAG_CHN_ECHO, 0x4 @ [bit] echo phase | |
.equ FLAG_CHN_ATTACK, 0x3 @ [bit] attack phase | |
.equ FLAG_CHN_DECAY, 0x2 @ [bit] decay phase | |
.equ FLAG_CHN_SUSTAIN, 0x1 @ [bit] sustain phase | |
/* CHN_MODE flags */ | |
.equ MODE_FIXED_FREQ, 0x8 @ [bit] set to disable resampling (i.e. playback with output rate) | |
.equ MODE_REVERSE, 0x10 @ [bit] set to reverse sample playback | |
.equ MODE_COMP, 0x30 @ [bit] is wave being played compressed or reversed (TODO: rename flag) | |
.equ MODE_SYNTH, 0x40 @ [bit] READ ONLY, indicates synthzied output | |
/* variables of the engine work area */ | |
.equ VAR_REVERB, 0x5 @ [byte] 0-127 = reverb level | |
.equ VAR_MAX_CHN, 0x6 @ [byte] maximum channels to process | |
.equ VAR_MASTER_VOL, 0x7 @ [byte] PCM master volume | |
.equ VAR_DEF_PITCH_FAC, 0x18 @ [word] this value gets multiplied with the sample rate for the inter sample distance | |
.equ VAR_FIRST_CHN, 0x50 @ [CHN struct] relative offset to channel array | |
/* just some more defines */ | |
.equ REG_DMA3_SRC, 0x040000D4 | |
.equ ARM_OP_LEN, 0x4 | |
.syntax divided | |
thumb_func_start SoundMainRAM | |
SoundMainRAM: | |
main_mixer: | |
/* load Reverb level and check if we need to apply it */ | |
STR R4, [SP, #ARG_BUFFER_POS_INDEX_HINT] | |
ADR R2, is_buffer_init | |
LDRB R0, [R2] | |
CMP R0, #0 | |
BNE C_setup_channel_state_loop | |
/* if buffer not initialized, clear first */ | |
LDR R3, hq_buffer | |
MOV R1, R8 | |
MOV R4, #0 | |
MOV R5, #0 | |
MOV R6, #0 | |
MOV R7, #0 | |
LSR R1, #3 | |
BCC C_clear_buffer_align_8 | |
STMIA R3!, {R4, R5, R6, R7} | |
C_clear_buffer_align_8: | |
LSR R1, #1 | |
BCC C_clear_buffer_align_16 | |
STMIA R3!, {R4, R5, R6, R7} | |
STMIA R3!, {R4, R5, R6, R7} | |
C_clear_buffer_align_16: | |
STMIA R3!, {R4, R5, R6, R7} | |
STMIA R3!, {R4, R5, R6, R7} | |
STMIA R3!, {R4, R5, R6, R7} | |
STMIA R3!, {R4, R5, R6, R7} | |
SUB R1, #1 | |
BGT C_clear_buffer_align_16 | |
MOV R1, #1 | |
STRB R1, [R2] | |
B C_setup_channel_state_loop | |
.align 2 | |
is_buffer_init: | |
.byte 0x0 | |
.align 1 | |
C_setup_channel_state_loop: | |
/* | |
* okay, before the actual mixing starts | |
* the volume and envelope calculation takes place | |
*/ | |
MOV R4, R8 @ R4 = buffer length | |
/* | |
* this stroes the buffer length to a backup location | |
*/ | |
STR R4, [SP, #ARG_FRAME_LENGTH] | |
/* init channel loop */ | |
LDR R4, [SP, #ARG_PCM_STRUCT] @ R4 = main work area pointer | |
LDR R0, [R4, #VAR_DEF_PITCH_FAC] @ R0 = samplingrate pitch factor | |
MOV R12, R0 | |
LDRB R0, [R4, #VAR_MAX_CHN] | |
ADD R4, #VAR_FIRST_CHN @ R4 = Base channel Offset (Channel #0) | |
C_channel_state_loop: | |
/* this is the main channel processing loop */ | |
STR R0, [SP, #ARG_REMAIN_CHN] | |
LDR R3, [R4, #CHN_WAVE_OFFSET] | |
LDRB R6, [R4, #CHN_STATUS] @ R6 will hold the channel status | |
MOVS R0, #0xC7 @ check if any of the channel status flags is set | |
TST R0, R6 @ check if none of the flags is set | |
BEQ C_skip_channel | |
/* check channel flags */ | |
LSL R0, R6, #25 @ shift over the FLAG_CHN_INIT to CARRY | |
BCC C_adsr_echo_check @ continue with normal channel procedure | |
/* check leftmost bit */ | |
BMI C_stop_channel @ FLAG_CHN_INIT | FLAG_CHN_RELEASE -> stop directly | |
/* channel init procedure */ | |
MOVS R6, #FLAG_CHN_ATTACK | |
MOVS R0, R3 @ R0 = CHN_WAVE_OFFSET | |
ADD R0, #WAVE_DATA @ R0 = wave data offset | |
/* Pokemon games seem to init channels differently than other m4a games */ | |
.if POKE_INIT==0 | |
STR R0, [R4, #CHN_POSITION_ABS] | |
LDR R0, [R3, #WAVE_LENGTH] | |
STR R0, [R4, #CHN_SAMPLE_COUNTDOWN] | |
.else | |
LDR R1, [R4, #CHN_SAMPLE_COUNTDOWN] | |
ADD R0, R0, R1 | |
STR R0, [R4, #CHN_POSITION_ABS] | |
LDR R0, [R3, #WAVE_LENGTH] | |
SUB R0, R0, R1 | |
STR R0, [R4, #CHN_SAMPLE_COUNTDOWN] | |
.endif | |
MOVS R5, #0 @ initial envelope = #0 | |
STRB R5, [R4, #CHN_ADSR_LEVEL] | |
STR R5, [R4, #CHN_FINE_POSITION] | |
LDRB R2, [R3, #WAVE_LOOP_FLAG] | |
LSR R0, R2, #6 | |
BEQ C_adsr_attack | |
/* loop enabled here */ | |
MOVS R0, #FLAG_CHN_LOOP | |
ORR R6, R0 | |
B C_adsr_attack | |
C_adsr_echo_check: | |
/* this is the normal ADSR procedure without init */ | |
LDRB R5, [R4, #CHN_ADSR_LEVEL] | |
LSL R0, R6, #29 @ FLAG_CHN_ECHO --> bit 31 (sign bit) | |
BPL C_adsr_release_check | |
/* pseudo echo handler */ | |
LDRB R0, [R4, #CHN_ECHO_REMAIN] | |
SUB R0, #1 | |
STRB R0, [R4, #CHN_ECHO_REMAIN] | |
BHI C_channel_vol_calc @ continue normal if channel is still on | |
C_stop_channel: | |
MOVS R0, #0 | |
STRB R0, [R4, #CHN_STATUS] | |
C_skip_channel: | |
/* go to end of the channel loop */ | |
B C_end_channel_state_loop | |
C_adsr_release_check: | |
LSL R0, R6, #25 @ FLAG_CHN_RELEASE --> bit 31 (sign bit) | |
BPL C_adsr_decay_check | |
/* release handler */ | |
LDRB R0, [R4, #CHN_RELEASE] | |
@SUB R0, #0xFF @ linear decay; TODO make option for triggering it | |
@SUB R0, #1 | |
@ADD R5, R5, R0 | |
MUL R5, R5, R0 | |
LSR R5, #8 | |
BLE C_adsr_released | |
/* pseudo echo init handler */ | |
LDRB R0, [R4, #CHN_ECHO_VOL] | |
CMP R5, R0 | |
BHI C_channel_vol_calc | |
C_adsr_released: | |
/* if volume released to #0 */ | |
LDRB R5, [R4, #CHN_ECHO_VOL] | |
CMP R5, #0 | |
BEQ C_stop_channel | |
/* pseudo echo volume handler */ | |
MOVS R0, #FLAG_CHN_ECHO | |
ORR R6, R0 @ set the echo flag | |
B C_adsr_save_and_finalize | |
C_adsr_decay_check: | |
/* check if decay is active */ | |
MOVS R2, #(FLAG_CHN_DECAY+FLAG_CHN_SUSTAIN) | |
AND R2, R6 | |
CMP R2, #FLAG_CHN_DECAY | |
BNE C_adsr_attack_check @ decay not active yet | |
/* decay handler */ | |
LDRB R0, [R4, #CHN_DECAY] | |
MUL R5, R5, R0 | |
LSR R5, R5, #8 | |
LDRB R0, [R4, #CHN_SUSTAIN] | |
CMP R5, R0 | |
BHI C_channel_vol_calc @ sample didn't decay yet | |
/* sustain handler */ | |
MOVS R5, R0 @ current level = sustain level | |
BEQ C_adsr_released @ sustain level #0 --> branch | |
/* step to next phase otherweise */ | |
B C_adsr_next_state | |
C_adsr_attack_check: | |
/* attack handler */ | |
CMP R2, #FLAG_CHN_ATTACK | |
BNE C_channel_vol_calc @ if it isn't in attack attack phase, it has to be in sustain (keep vol) --> branch | |
C_adsr_attack: | |
/* apply attack summand */ | |
LDRB R0, [R4, #CHN_ATTACK] | |
ADD R5, R0 | |
CMP R5, #0xFF | |
BLO C_adsr_save_and_finalize | |
/* cap attack at 0xFF */ | |
MOVS R5, #0xFF | |
C_adsr_next_state: | |
/* switch to next adsr phase */ | |
SUB R6, #1 | |
C_adsr_save_and_finalize: | |
/* store channel status */ | |
STRB R6, [R4, #CHN_STATUS] | |
C_channel_vol_calc: | |
/* store the calculated ADSR level */ | |
STRB R5, [R4, #CHN_ADSR_LEVEL] | |
/* apply master volume */ | |
LDR R0, [SP, #ARG_PCM_STRUCT] | |
LDRB R0, [R0, #VAR_MASTER_VOL] | |
ADD R0, #1 | |
MUL R5, R0 | |
/* left side volume */ | |
LDRB R0, [R4, #CHN_VOL_2] | |
MUL R0, R5 | |
LSR R0, #13 | |
MOV R10, R0 @ R10 = left volume | |
/* right side volume */ | |
LDRB R0, [R4, #CHN_VOL_1] | |
MUL R0, R5 | |
LSR R0, #13 | |
MOV R11, R0 @ R11 = right volume | |
/* | |
* Now we get closer to actual mixing: | |
* For looped samples some additional operations are required | |
*/ | |
MOVS R0, #FLAG_CHN_LOOP | |
AND R0, R6 | |
BEQ C_skip_sample_loop_setup | |
/* loop setup handler */ | |
ADD R3, #WAVE_LOOP_START | |
LDMIA R3!, {R0, R1} @ R0 = loop start, R1 = loop end | |
ADD R3, R0 @ R3 = loop start position (absolute) | |
STR R3, [SP, #ARG_LOOP_START_POS] | |
SUB R0, R1, R0 | |
C_skip_sample_loop_setup: | |
/* do the rest of the setup */ | |
STR R0, [SP, #ARG_LOOP_LENGTH] @ if loop is off --> R0 = 0x0 | |
LDR R5, hq_buffer | |
LDR R2, [R4, #CHN_SAMPLE_COUNTDOWN] | |
LDR R3, [R4, #CHN_POSITION_ABS] | |
LDRB R0, [R4, #CHN_MODE] | |
ADR R1, C_mixing_setup | |
BX R1 | |
.align 2 | |
hq_buffer: | |
.word hq_buffer_ptr | |
.arm | |
.align 2 | |
C_mixing_setup: | |
/* frequency and mixing loading routine */ | |
LDR R8, [SP, #ARG_FRAME_LENGTH] | |
ORRS R11, R11, R10, LSL#16 @ R11 = 00LL00RR | |
BEQ C_mixing_epilogue @ volume #0 --> branch and skip channel processing | |
/* normal processing otherwise */ | |
TST R0, #MODE_FIXED_FREQ | |
BNE C_setup_fixed_freq_mixing | |
TST R0, #MODE_COMP | |
BNE C_setup_special_mixing @ compressed? --> branch | |
STMFD SP!, {R4, R9, R12} | |
/* | |
* This mixer supports 4 different kind of synthesized sounds | |
* They are triggered if there is no samples to play | |
* This get's checked below | |
*/ | |
MOVS R2, R2 | |
ORREQ R0, R0, #MODE_SYNTH | |
STREQB R0, [R4, #CHN_MODE] | |
ADD R4, R4, #CHN_FINE_POSITION | |
LDMIA R4, {R7, LR} @ R7 = Fine Position, LR = Frequency | |
MUL R4, LR, R12 @ R4 = inter sample steps = output rate factor * samplerate | |
/* now the first samples get loaded */ | |
LDRSB R6, [R3], #1 | |
LDRSB R12, [R3] | |
TST R0, #MODE_SYNTH | |
BNE C_setup_synth | |
/* incase no synth mode should be used, code contiues here */ | |
SUB R12, R12, R6 @ R12 = DELTA | |
/* | |
* Mixing goes with volume ranges 0-127 | |
* They come in 0-255 --> divide by 2 | |
*/ | |
MOVS R11, R11, LSR#1 | |
ADC R11, R11, #0x8000 | |
BIC R11, R11, #0xFF00 | |
MOV R1, R7 @ R1 = inter sample position | |
/* | |
* There is 2 different mixing codepaths for uncompressed data | |
* path 1: fast mixing, but doesn't supports loop or stop | |
* path 2: not so fast but supports sample loops / stop | |
* This checks if there is enough samples aviable for path 1. | |
* important: R0 is expected to be #0 | |
*/ | |
UMLAL R1, R0, R4, R8 | |
MOV R1, R1, LSR#23 | |
ORR R0, R1, R0, LSL#9 | |
CMP R2, R0 @ actual comparison | |
BLE C_setup_unbuffered_mixing @ if not enough samples are available for path 1 --> branch | |
/* | |
* This is the mixer path 1. | |
* The interesting thing here is that the code will | |
* buffer enough samples on stack if enough space | |
* on stack is available (or goes over the limit of 0x400 bytes) | |
*/ | |
SUB R2, R2, R0 | |
LDR R10, upper_stack_bounds | |
ADD R10, R10, R0 | |
CMP R10, SP | |
ADD R10, R3, R0 | |
/* | |
* R2 = remaining samples after processing | |
* R10 = final sample position | |
* SP = original stack location | |
* These values will get reloaded after channel processing | |
* due to the lack of registers. | |
*/ | |
STMFD SP!, {R2, R10} | |
CMPCC R0, #0x400 @ > 0x400 bytes --> read directly from ROM rather than buffered | |
MOV R10, SP | |
BCS C_select_highspeed_codepath | |
/* | |
* The code below inits the DMA to read word aligned | |
* samples from ROM to stack | |
*/ | |
BIC R1, R3, #3 | |
MOV R9, #0x04000000 | |
ADD R9, R9, #0xD4 | |
ADD R0, R0, #7 | |
MOV R0, R0, LSR#2 | |
SUB SP, SP, R0, LSL#2 | |
AND R3, R3, #3 | |
ADD R3, R3, SP | |
ORR LR, R0, #0x84000000 | |
STMIA R9, {R1, SP, LR} @ actually starts the DMA | |
/* Somehow is neccesary for some games not to break */ | |
.if DMA_FIX==1 | |
MOV R0, #0 | |
MOV R1, #0 | |
MOV R2, #0 | |
STMIA R9, {R0, R1, R2} | |
.endif | |
C_select_highspeed_codepath: | |
STMFD SP!, {R10} @ save original SP for VLA | |
/* | |
* This code decides which piece of code to load | |
* depending on playback-rate / default-rate ratio. | |
* Modes > 1.0 run with different volume levels. | |
* R4 = inter sample step | |
*/ | |
ADR R0, high_speed_code_resource @ loads the base pointer of the code | |
SUBS R4, R4, #0x800000 | |
MOVPL R11, R11, LSL#1 @ if >= 1.0* 0-127 --> 0-254 volume level | |
ADDPL R0, R0, #(ARM_OP_LEN*6) @ 6 instructions further | |
SUBPLS R4, R4, #0x800000 @ if >= 2.0* | |
ADDPL R0, R0, #(ARM_OP_LEN*6) | |
ADDPL R4, R4, #0x800000 | |
LDR R2, previous_fast_code | |
CMP R0, R2 @ code doesn't need to be reloaded if it's already in place | |
BEQ C_skip_fast_mixing_creation | |
/* This loads the needed code to RAM */ | |
STR R0, previous_fast_code | |
LDMIA R0, {R0-R2, R8-R10} @ load 6 opcodes | |
ADR LR, fast_mixing_instructions | |
C_fast_mixing_creation_loop: | |
/* paste code to destination, see below for patterns */ | |
STMIA LR, {R0, R1} | |
ADD LR, LR, #(ARM_OP_LEN*38) | |
STMIA LR, {R0, R1} | |
SUB LR, LR, #(ARM_OP_LEN*35) | |
STMIA LR, {R2, R8-R10} | |
ADD LR, LR, #(ARM_OP_LEN*38) | |
STMIA LR, {R2, R8-R10} | |
SUB LR, LR, #(ARM_OP_LEN*32) | |
ADDS R5, R5, #0x40000000 @ do that for 4 blocks | |
BCC C_fast_mixing_creation_loop | |
LDR R8, [SP] @ restore R8 with the frame length | |
LDR R8, [R8, #(ARG_FRAME_LENGTH + 0x8 + 0xC)] | |
C_skip_fast_mixing_creation: | |
MOV R2, #0xFF000000 @ load the fine position overflow bitmask | |
C_fast_mixing_loop: | |
/* This is the actual processing and interpolation code loop; NOPs will be replaced by the code above */ | |
LDMIA R5, {R0, R1, R10, LR} @ load 4 stereo samples to Registers | |
MUL R9, R7, R12 | |
fast_mixing_instructions: | |
NOP @ Block #1 | |
NOP | |
MLANE R0, R11, R9, R0 | |
NOP | |
NOP | |
NOP | |
NOP | |
BIC R7, R7, R2, ASR#1 | |
MULNE R9, R7, R12 | |
NOP @ Block #2 | |
NOP | |
MLANE R1, R11, R9, R1 | |
NOP | |
NOP | |
NOP | |
NOP | |
BIC R7, R7, R2, ASR#1 | |
MULNE R9, R7, R12 | |
NOP @ Block #3 | |
NOP | |
MLANE R10, R11, R9, R10 | |
NOP | |
NOP | |
NOP | |
NOP | |
BIC R7, R7, R2, ASR#1 | |
MULNE R9, R7, R12 | |
NOP @ Block #4 | |
NOP | |
MLANE LR, R11, R9, LR | |
NOP | |
NOP | |
NOP | |
NOP | |
BIC R7, R7, R2, ASR#1 | |
STMIA R5!, {R0, R1, R10, LR} @ write 4 stereo samples | |
LDMIA R5, {R0, R1, R10, LR} @ load the next 4 stereo samples | |
MULNE R9, R7, R12 | |
NOP @ Block #1 | |
NOP | |
MLANE R0, R11, R9, R0 | |
NOP | |
NOP | |
NOP | |
NOP | |
BIC R7, R7, R2, ASR#1 | |
MULNE R9, R7, R12 | |
NOP @ Block #2 | |
NOP | |
MLANE R1, R11, R9, R1 | |
NOP | |
NOP | |
NOP | |
NOP | |
BIC R7, R7, R2, ASR#1 | |
MULNE R9, R7, R12 | |
NOP @ Block #3 | |
NOP | |
MLANE R10, R11, R9, R10 | |
NOP | |
NOP | |
NOP | |
NOP | |
BIC R7, R7, R2, ASR#1 | |
MULNE R9, R7, R12 | |
NOP @ Block #4 | |
NOP | |
MLANE LR, R11, R9, LR | |
NOP | |
NOP | |
NOP | |
NOP | |
BIC R7, R7, R2, ASR#1 | |
STMIA R5!, {R0, R1, R10, LR} @ write 4 stereo samples | |
SUBS R8, R8, #8 | |
BGT C_fast_mixing_loop | |
/* restore previously saved values */ | |
LDMFD SP, {SP} @ reload original stack pointer from VLA | |
LDMFD SP!, {R2, R3} | |
B C_end_mixing | |
/* Various variables for the cached mixer */ | |
.align 2 | |
upper_stack_bounds: | |
.word 0x03007910 | |
previous_fast_code: | |
.word 0x0 /* mark as invalid initially */ | |
/* Those instructions below are used by the high speed loop self modifying code */ | |
high_speed_code_resource: | |
/* Block for Mix Freq < 1.0 * Output Frequency */ | |
MOV R9, R9, ASR#22 | |
ADDS R9, R9, R6, LSL#1 | |
ADDS R7, R7, R4 | |
ADDPL R6, R12, R6 | |
LDRPLSB R12, [R3, #1]! | |
SUBPLS R12, R12, R6 | |
/* Block for Mix Freq > 1.0 AND < 2.0 * Output Frequency */ | |
ADDS R9, R6, R9, ASR#23 | |
ADD R6, R12, R6 | |
ADDS R7, R7, R4 | |
LDRPLSB R6, [R3, #1]! | |
LDRSB R12, [R3, #1]! | |
SUBS R12, R12, R6 | |
/* Block for Mix Freq > 2.0 * Output Frequency */ | |
ADDS R9, R6, R9, ASR#23 | |
ADD R7, R7, R4 | |
ADD R3, R3, R7, LSR#23 | |
LDRSB R6, [R3] | |
LDRSB R12, [R3, #1]! | |
SUBS R12, R12, R6 | |
/* incase a loop or end occurs during mixing, this code is used */ | |
C_setup_unbuffered_mixing: | |
ADD R5, R5, R8, LSL#2 @ R5 = End of HQ buffer | |
/* This below is the unbuffered mixing loop. R6 = base sample, R12 diff to next */ | |
C_unbuffered_mixing_loop: | |
MUL R9, R7, R12 | |
MOV R9, R9, ASR#22 | |
ADDS R9, R9, R6, LSL#1 | |
LDRNE R0, [R5, -R8, LSL#2] | |
MLANE R0, R11, R9, R0 | |
STRNE R0, [R5, -R8, LSL#2] | |
ADD R7, R7, R4 | |
MOVS R9, R7, LSR#23 | |
BEQ C_unbuffered_mixing_skip_load @ skip the mixing load if it isn't required | |
SUBS R2, R2, R7, LSR#23 | |
BLLE C_mixing_loop_or_end | |
SUBS R9, R9, #1 | |
ADDEQ R6, R12, R6 | |
@RETURN LOCATION FROM LOOP HANDLER | |
LDRNESB R6, [R3, R9]! | |
LDRSB R12, [R3, #1]! | |
SUB R12, R12, R6 | |
BIC R7, R7, #0x3F800000 | |
C_unbuffered_mixing_skip_load: | |
SUBS R8, R8, #1 @ reduce the sample count for the buffer by #1 | |
BGT C_unbuffered_mixing_loop | |
C_end_mixing: | |
SUB R3, R3, #1 @ because the mixer always needs 1 byte lookahead, this reverts it | |
LDMFD SP!, {R4, R9, R12} | |
STR R7, [R4, #CHN_FINE_POSITION] | |
B C_mixing_end_store | |
C_mixing_loop_or_end: | |
/* This loads the loop information end loops incase it should */ | |
ADD R3, SP, #ARG_LOOP_START_POS+0xC | |
LDMIA R3, {R3, R6} @ R3 = Loop Start; R6 = Loop Length | |
CMP R6, #0 @ check if loop is enabled; if Loop is enabled R6 is != 0 | |
RSBNE R9, R2, #0 @ loop wraparound logic | |
ADDNE R2, R6, R2 | |
ADDNE PC, LR, #(ARM_OP_LEN*2) | |
LDMFD SP!, {R4, R9, R12} | |
B C_mixing_end_and_stop_channel @ R6 == 0 (always) | |
C_fixed_mixing_loop_or_end: | |
LDR R2, [SP, #ARG_LOOP_LENGTH+0x8] | |
MOVS R6, R2 @ copy it to R6 and check whether loop is disabled | |
LDRNE R3, [SP, #ARG_LOOP_START_POS+0x8] | |
BXNE LR @ if it loops return to mixing function, if it doesn't go on end mixing | |
LDMFD SP!, {R4, R9} | |
C_mixing_end_and_stop_channel: | |
STRB R6, [R4] @ update channel flag with chn halt | |
B C_mixing_epilogue | |
/* These are used for the fixed freq mixer */ | |
fixed_mixing_code_resource: | |
MOVS R6, R10, LSL#24 | |
MOVS R6, R6, ASR#24 | |
MOVS R6, R10, LSL#16 | |
MOVS R6, R6, ASR#24 | |
MOVS R6, R10, LSL#8 | |
MOVS R6, R6, ASR#24 | |
MOVS R6, R10, ASR#24 | |
LDMIA R3!, {R10} @ load chunk of samples | |
MOVS R6, R10, LSL#24 | |
MOVS R6, R6, ASR#24 | |
MOVS R6, R10, LSL#16 | |
MOVS R6, R6, ASR#24 | |
MOVS R6, R10, LSL#8 | |
MOVS R6, R6, ASR#24 | |
LDMFD SP!, {R4, R9, R12} | |
C_setup_fixed_freq_mixing: | |
STMFD SP!, {R4, R9} | |
C_fixed_mixing_length_check: | |
MOV LR, R2 @ sample countdown | |
CMP R2, R8 | |
MOVGT LR, R8 @ min(buffer_size, sample_countdown) | |
SUB LR, LR, #1 | |
MOVS LR, LR, LSR#2 | |
BEQ C_fixed_mixing_process_rest @ <= 3 samples to process | |
SUB R8, R8, LR, LSL#2 @ subtract the amount of samples we need to process from the buffer length | |
SUB R2, R2, LR, LSL#2 @ subtract the amount of samples we need to process from the remaining samples | |
ADR R1, fixed_mixing_instructions | |
ADR R0, fixed_mixing_code_resource | |
MOV R9, R3, LSL#30 | |
ADD R0, R0, R9, LSR#27 @ alignment * 8 + resource offset = new resource offset | |
LDMIA R0!, {R6, R7, R9, R10} @ load and write instructions | |
STMIA R1, {R6, R7} | |
ADD R1, R1, #0xC | |
STMIA R1, {R9, R10} | |
ADD R1, R1, #0xC | |
LDMIA R0, {R6, R7, R9, R10} | |
STMIA R1, {R6, R7} | |
ADD R1, R1, #0xC | |
STMIA R1, {R9, R10} | |
LDMIA R3!, {R10} @ load 4 samples from ROM | |
C_fixed_mixing_loop: | |
LDMIA R5, {R0, R1, R7, R9} @ load 4 samples from hq buffer | |
fixed_mixing_instructions: | |
NOP | |
NOP | |
MLANE R0, R11, R6, R0 @ add new sample if neccessary | |
NOP | |
NOP | |
MLANE R1, R11, R6, R1 | |
NOP | |
NOP | |
MLANE R7, R11, R6, R7 | |
NOP | |
NOP | |
MLANE R9, R11, R6, R9 | |
STMIA R5!, {R0, R1, R7, R9} @ write samples to the mixing buffer | |
SUBS LR, LR, #1 | |
BNE C_fixed_mixing_loop | |
SUB R3, R3, #4 @ we'll need to load this block again, so rewind a bit | |
C_fixed_mixing_process_rest: | |
MOV R1, #4 @ repeat the loop #4 times to completley get rid of alignment errors | |
C_fixed_mixing_unaligned_loop: | |
LDR R0, [R5] | |
LDRSB R6, [R3], #1 | |
MLA R0, R11, R6, R0 | |
STR R0, [R5], #4 | |
SUBS R2, R2, #1 | |
BLEQ C_fixed_mixing_loop_or_end | |
SUBS R1, R1, #1 | |
BGT C_fixed_mixing_unaligned_loop | |
SUBS R8, R8, #4 | |
BGT C_fixed_mixing_length_check @ repeat the mixing procedure until the buffer is filled | |
LDMFD SP!, {R4, R9} | |
C_mixing_end_store: | |
STR R2, [R4, #CHN_SAMPLE_COUNTDOWN] | |
STR R3, [R4, #CHN_POSITION_ABS] | |
C_mixing_epilogue: | |
ADR R0, (C_end_channel_state_loop+1) | |
BX R0 | |
.thumb | |
C_end_channel_state_loop: | |
LDR R0, [SP, #ARG_REMAIN_CHN] | |
SUB R0, #1 | |
BLE C_main_mixer_return | |
ADD R4, #0x40 | |
B C_channel_state_loop | |
C_main_mixer_return: | |
ADR R5, V_noise_shape | |
LDRB R4, [R5, #0] @ left noise shape | |
LSL R4, R4, #16 | |
LDRB R5, [R5, #1] @ right noise shape | |
LSL R5, R5, #16 | |
ADR R0, C_downsampler | |
BX R0 | |
V_noise_shape: | |
.byte 0, 0 | |
.arm | |
.align 2 | |
C_downsampler: | |
LDR R8, [SP, #ARG_FRAME_LENGTH] | |
LDR R9, [SP, #ARG_BUFFER_POS] | |
LDR R10, hq_buffer | |
MOV R11, #0xFF000000 | |
MOV LR, #0xC0000000 | |
C_downsampler_loop: | |
LDMIA R10, {R0, R1, R2, R3} | |
ADD R12, R4, R0 @ left sample #1 | |
ADDS R4, R12, R12 | |
EORVS R12, LR, R4, ASR#31 | |
AND R4, R12, #0x007F0000 | |
AND R6, R11, R12, LSL#1 | |
ADD R0, R5, R0, LSL#16 @ right | |
ADDS R5, R0, R0 | |
EORVS R0, LR, R5, ASR#31 | |
AND R5, R0, #0x007F0000 | |
AND R7, R11, R0, LSL#1 | |
ADD R12, R4, R1 @ left sample #2 | |
ADDS R4, R12, R12 | |
EORVS R12, LR, R4, ASR#31 | |
AND R4, R12, #0x007F0000 | |
AND R12, R11, R12, LSL#1 | |
ORR R6, R12, R6, LSR#8 | |
ADD R1, R5, R1, LSL#16 @ right | |
ADDS R5, R1, R1 | |
EORVS R1, LR, R5, ASR#31 | |
AND R5, R1, #0x007F0000 | |
AND R1, R11, R1, LSL#1 | |
ORR R7, R1, R7, LSR#8 | |
ADD R12, R4, R2 @ left sample #3 | |
ADDS R4, R12, R12 | |
EORVS R12, LR, R4, ASR#31 | |
AND R4, R12, #0x007F0000 | |
AND R12, R11, R12, LSL#1 | |
ORR R6, R12, R6, LSR#8 | |
ADD R2, R5, R2, LSL#16 @ right | |
ADDS R5, R2, R2 | |
EORVS R2, LR, R5, ASR#31 | |
AND R5, R2, #0x007F0000 | |
AND R2, R11, R2, LSL#1 | |
ORR R7, R2, R7, LSR#8 | |
ADD R12, R4, R3 @ left sample #4 | |
ADDS R4, R12, R12 | |
EORVS R12, LR, R4, ASR#31 | |
AND R4, R12, #0x007F0000 | |
AND R12, R11, R12, LSL#1 | |
ORR R6, R12, R6, LSR#8 | |
ADD R3, R5, R3, LSL#16 @ right | |
ADDS R5, R3, R3 | |
EORVS R3, LR, R5, ASR#31 | |
AND R5, R3, #0x007F0000 | |
AND R3, R11, R3, LSL#1 | |
ORR R7, R3, R7, LSR#8 | |
STR R6, [R9, #0x630] | |
STR R7, [R9], #4 | |
MOV R0, #0 | |
MOV R1, #0 | |
MOV R2, #0 | |
MOV R3, #0 | |
STMIA R10!, {R0, R1, R2, R3} | |
SUBS R8, #4 | |
BGT C_downsampler_loop | |
ADR R1, V_noise_shape | |
ADR R0, (C_downsampler_return+1) | |
BX R0 | |
.pool | |
.align 1 | |
.thumb | |
C_downsampler_return: | |
LSR R4, #16 | |
STRB R4, [R1, #0] | |
LSR R5, #16 | |
STRB R5, [R1, #1] | |
LDR R0, [SP, #ARG_PCM_STRUCT] | |
LDR R3, mixer_finished_status @ this is used to indicate the interrupt handler the rendering was finished properly | |
STR R3, [R0] | |
ADD SP, SP, #0x1C | |
POP {R0-R7} | |
MOV R8, R0 | |
MOV R9, R1 | |
MOV R10, R2 | |
MOV R11, R3 | |
POP {R3} | |
BX R3 | |
.align 2 | |
mixer_finished_status: | |
.word 0x68736D53 | |
.arm | |
.align 2 | |
C_setup_synth: | |
CMP R12, #0 | |
BNE C_check_synth_saw | |
/* modulating pulse wave */ | |
LDRB R6, [R3, #SYNTH_WIDTH_CHANGE_1] | |
ADD R2, R2, R6, LSL#24 | |
LDRB R6, [R3, #SYNTH_WIDTH_CHANGE_2] | |
ADDS R6, R2, R6, LSL#24 | |
MVNMI R6, R6 | |
MOV R10, R6, LSR#8 | |
LDRB R1, [R3, #SYNTH_MOD_AMOUNT] | |
LDRB R0, [R3, #SYNTH_BASE_WAVE_DUTY] | |
MOV R0, R0, LSL#24 | |
MLA R6, R10, R1, R0 @ calculate the final duty cycle with the offset, and intensity * rotating duty cycle amount | |
STMFD SP!, {R2, R3, R9, R12} | |
C_synth_pulse_loop: | |
LDMIA R5, {R0-R3, R9, R10, R12, LR} @ load 8 samples | |
CMP R7, R6 @ Block #1 | |
ADDLO R0, R0, R11, LSL#6 | |
SUBHS R0, R0, R11, LSL#6 | |
ADDS R7, R7, R4, LSL#3 | |
CMP R7, R6 @ Block #2 | |
ADDLO R1, R1, R11, LSL#6 | |
SUBHS R1, R1, R11, LSL#6 | |
ADDS R7, R7, R4, LSL#3 | |
CMP R7, R6 @ Block #3 | |
ADDLO R2, R2, R11, LSL#6 | |
SUBHS R2, R2, R11, LSL#6 | |
ADDS R7, R7, R4, LSL#3 | |
CMP R7, R6 @ Block #4 | |
ADDLO R3, R3, R11, LSL#6 | |
SUBHS R3, R3, R11, LSL#6 | |
ADDS R7, R7, R4, LSL#3 | |
CMP R7, R6 @ Block #5 | |
ADDLO R9, R9, R11, LSL#6 | |
SUBHS R9, R9, R11, LSL#6 | |
ADDS R7, R7, R4, LSL#3 | |
CMP R7, R6 @ Block #6 | |
ADDLO R10, R10, R11, LSL#6 | |
SUBHS R10, R10, R11, LSL#6 | |
ADDS R7, R7, R4, LSL#3 | |
CMP R7, R6 @ Block #7 | |
ADDLO R12, R12, R11, LSL#6 | |
SUBHS R12, R12, R11, LSL#6 | |
ADDS R7, R7, R4, LSL#3 | |
CMP R7, R6 @ Block #8 | |
ADDLO LR, LR, R11, LSL#6 | |
SUBHS LR, LR, R11, LSL#6 | |
ADDS R7, R7, R4, LSL#3 | |
STMIA R5!, {R0-R3, R9, R10, R12, LR} @ write 8 samples | |
SUBS R8, R8, #8 | |
BGT C_synth_pulse_loop | |
LDMFD SP!, {R2, R3, R9, R12} | |
B C_end_mixing | |
C_check_synth_saw: | |
/* | |
* This is actually not a true saw wave | |
* but looks pretty similar | |
* (has a jump in the middle of the wave) | |
*/ | |
SUBS R12, R12, #1 | |
BNE C_synth_triangle | |
MOV R6, #0x300 | |
MOV R11, R11, LSR#1 | |
BIC R11, R11, #0xFF00 | |
MOV R12, #0x70 | |
C_synth_saw_loop: | |
LDMIA R5, {R0, R1, R10, LR} @ load 4 samples from memory | |
ADDS R7, R7, R4, LSL#3 @ Block #1 (some oscillator type code) | |
RSB R9, R12, R7, LSR#24 | |
MOV R6, R7, LSL#1 | |
SUB R9, R9, R6, LSR#27 | |
ADDS R2, R9, R2, ASR#1 | |
MLANE R0, R11, R2, R0 | |
ADDS R7, R7, R4, LSL#3 @ Block #2 | |
RSB R9, R12, R7, LSR#24 | |
MOV R6, R7, LSL#1 | |
SUB R9, R9, R6, LSR#27 | |
ADDS R2, R9, R2, ASR#1 | |
MLANE R1, R11, R2, R1 | |
ADDS R7, R7, R4, LSL#3 @ Block #3 | |
RSB R9, R12, R7, LSR#24 | |
MOV R6, R7, LSL#1 | |
SUB R9, R9, R6, LSR#27 | |
ADDS R2, R9, R2, ASR#1 | |
MLANE R10, R11, R2, R10 | |
ADDS R7, R7, R4, LSL#3 @ Block #4 | |
RSB R9, R12, R7, LSR#24 | |
MOV R6, R7, LSL#1 | |
SUB R9, R9, R6, LSR#27 | |
ADDS R2, R9, R2, ASR#1 | |
MLANE LR, R11, R2, LR | |
STMIA R5!, {R0, R1, R10, LR} | |
SUBS R8, R8, #4 | |
BGT C_synth_saw_loop | |
B C_end_mixing | |
C_synth_triangle: | |
MOV R6, #0x80 | |
MOV R12, #0x180 | |
C_synth_triangle_loop: | |
LDMIA R5, {R0, R1, R10, LR} @ load samples from work buffer | |
ADDS R7, R7, R4, LSL#3 @ Block #1 | |
RSBPL R9, R6, R7, ASR#23 | |
SUBMI R9, R12, R7, LSR#23 | |
MLA R0, R11, R9, R0 | |
ADDS R7, R7, R4, LSL#3 @ Block #2 | |
RSBPL R9, R6, R7, ASR#23 | |
SUBMI R9, R12, R7, LSR#23 | |
MLA R1, R11, R9, R1 | |
ADDS R7, R7, R4, LSL#3 @ Block #3 | |
RSBPL R9, R6, R7, ASR#23 | |
SUBMI R9, R12, R7, LSR#23 | |
MLA R10, R11, R9, R10 | |
ADDS R7, R7, R4, LSL#3 @ Block #4 | |
RSBPL R9, R6, R7, ASR#23 | |
SUBMI R9, R12, R7, LSR#23 | |
MLA LR, R11, R9, LR | |
STMIA R5!, {R0, R1, R10, LR} | |
SUBS R8, R8, #4 @ subtract #4 from the remainging samples | |
BGT C_synth_triangle_loop | |
B C_end_mixing | |
.if ENABLE_DECOMPRESSION==1 | |
C_setup_special_mixing: | |
LDR R6, [R4, #CHN_WAVE_OFFSET] | |
LDRB R0, [R4] | |
TST R0, #FLAG_CHN_COMP | |
BNE C_setup_special_mixing_freq @ skip the setup procedure if it's running in compressed mode already | |
ORR R0, #FLAG_CHN_COMP | |
STRB R0, [R4] | |
LDRB R0, [R4, #CHN_MODE] | |
TST R0, #MODE_REVERSE | |
BEQ C_check_compression @ reversed mode not enabled? | |
LDR R1, [R6, #WAVE_LENGTH] @ calculate seek position for reverse playback | |
ADD R1, R1, R6, LSL#1 @ sorry, I don't actually understand that piece of code myself | |
ADD R1, R1, #0x20 | |
SUB R3, R1, R3 | |
STR R3, [R4, #CHN_POSITION_ABS] | |
C_check_compression: | |
LDRH R0, [R6] | |
CMP R0, #0 | |
BEQ C_setup_special_mixing_freq | |
SUB R3, R3, R6 | |
SUB R3, R3, #0x10 | |
STR R3, [R4, #CHN_POSITION_ABS] | |
C_setup_special_mixing_freq: | |
LDR R0, [R6, #WAVE_LOOP_START] | |
STR R0, [SP, #ARG_LOOP_START_POS] | |
STMFD SP!, {R4, R9, R12} | |
MOVS R11, R11, LSR#1 | |
ADC R11, R11, #0x8000 | |
BIC R11, R11, #0xFF00 | |
LDR R7, [R4, #CHN_FINE_POSITION] | |
LDR R1, [R4, #CHN_FREQUENCY] | |
LDRB R0, [R4, #CHN_MODE] | |
TST R0, #MODE_FIXED_FREQ | |
MOVNE R1, #0x800000 | |
MULEQ R1, R12, R1 @ default rate factor * frequency = sample steps | |
ADD R5, R5, R8, LSL#2 @ set the buffer pointer to the end of the channel, same as slow mixing mode | |
LDRH R0, [R6] | |
CMP R0, #0 | |
BEQ C_uncompressed_reverse_mixing_check | |
MOV R0, #0xFF000000 @ --> invalid channel mod | |
STR R0, [R4, #CHN_BLOCK_COUNT] | |
LDRB R0, [R4, #CHN_MODE] | |
TST R0, #MODE_REVERSE | |
BNE C_setup_compressed_reverse_mixing @ check again of reverse mixing is enabled | |
/* forward compressed mixing */ | |
BL F_bdpcm_decoder | |
MOV R6, R12 | |
ADD R3, R3, #1 | |
BL F_bdpcm_decoder | |
SUB R12, R12, R6 | |
@***** MIXING LOOP REGISTER USAGE ***********@ | |
@ R0: Sample to modify from buffer | |
@ R1: sample steps (MOVED FROM R4) | |
@ R2: remaining samples before loop/end | |
@ R3: sample position | |
@ R4: channel pointer | |
@ R5: pointer to the end of buffer | |
@ R6: Base sample | |
@ R7: fine position | |
@ R8: remaining samples for current buffer | |
@ R9: interpolated sample | |
@ R10: not used | |
@ R11: volume | |
@ R12: Delta Sample | |
@ LR: not used | |
@********************************************@ | |
C_compressed_mixing_loop: | |
MUL R9, R7, R12 @ check slow mixing for details, same procedure here | |
MOV R9, R9, ASR#22 | |
ADDS R9, R9, R6, LSL#1 | |
LDRNE R0, [R5, -R8, LSL#2] | |
MLANE R0, R11, R9, R0 | |
STRNE R0, [R5, -R8, LSL#2] | |
ADD R7, R7, R1 @ ### changed from R4 to R1 | |
MOVS R9, R7, LSR#23 | |
BEQ C_compressed_mixing_skip_load | |
SUBS R2, R2, R7, LSR#23 | |
BLLE C_mixing_loop_or_end | |
SUBS R9, R9, #1 | |
ADDEQ R6, R12, R6 | |
BEQ C_compressed_mixing_skip_base_load | |
ADD R3, R3, R9 @ equivalent to LDRNESB R6, [R3, R9]! | |
BL F_bdpcm_decoder | |
MOV R6, R12 | |
C_compressed_mixing_skip_base_load: | |
ADD R3, R3, #1 @ equivalent to LDRSB R12, [R3, #1]! | |
BL F_bdpcm_decoder | |
SUB R12, R12, R6 | |
BIC R7, R7, #0x3F800000 | |
C_compressed_mixing_skip_load: | |
SUBS R8, R8, #1 | |
BGT C_compressed_mixing_loop | |
B C_end_mixing | |
C_setup_compressed_reverse_mixing: | |
SUB R3, R3, #1 | |
BL F_bdpcm_decoder | |
MOV R6, R12 | |
SUB R3, R3, #1 | |
BL F_bdpcm_decoder | |
SUB R12, R12, R6 | |
C_compressed_reverse_mixing_loop: | |
MUL R9, R7, R12 | |
MOV R9, R9, ASR#22 | |
ADDS R9, R9, R6, LSL#1 | |
LDRNE R0, [R5, -R8, LSL#2] | |
MLANE R0, R11, R9, R0 | |
STRNE R0, [R5, -R8, LSL#2] | |
ADD R7, R7, R1 @ ### changed from R4 to R1 | |
MOVS R9, R7, LSR#23 | |
BEQ C_compressed_reverse_mixing_skip_load | |
SUBS R2, R2, R7, LSR#23 | |
BLLE C_mixing_loop_or_end | |
SUBS R9, R9, #1 | |
ADDEQ R6, R12, R6 | |
BEQ C_compressed_reverse_mixing_skip_base_load | |
SUB R3, R3, R9 | |
BL F_bdpcm_decoder | |
MOV R6, R12 | |
C_compressed_reverse_mixing_skip_base_load: | |
SUB R3, R3, #1 | |
BL F_bdpcm_decoder | |
SUB R12, R12, R6 | |
BIC R7, R7, #0x3F800000 | |
C_compressed_reverse_mixing_skip_load: | |
SUBS R8, R8, #1 | |
BGT C_compressed_reverse_mixing_loop | |
ADD R3, R3, #3 | |
B C_end_mixing | |
C_uncompressed_reverse_mixing_check: | |
LDRB R0, [R4, #1] | |
TST R0, #MODE_REVERSE @ check if reverse mode is even enabled (consistency) | |
BEQ C_end_mixing | |
LDRSB R6, [R3, #-1]! | |
LDRSB R12, [R3, #-1] | |
SUB R12, R12, R6 | |
C_uncompressed_reverse_mixing_loop: | |
MUL R9, R7, R12 | |
MOV R9, R9, ASR#22 | |
ADDS R9, R9, R6, LSL#1 | |
LDRNE R0, [R5, -R8, LSL#2] | |
MLANE R0, R11, R9, R0 | |
STRNE R0, [R5, -R8, LSL#2] | |
ADD R7, R7, R1 @ ### changed from R4 to R1 | |
MOVS R9, R7, LSR#23 | |
BEQ C_uncompressed_reverse_mixing_load_skip | |
SUBS R2, R2, R7, LSR#23 | |
BLLE C_mixing_loop_or_end | |
MOVS R9, R9 | |
ADDEQ R6, R12, R6 | |
LDRNESB R6, [R3, -R9]! | |
LDRSB R12, [R3, #-1] | |
SUB R12, R12, R6 | |
BIC R7, R7, #0x3F800000 | |
C_uncompressed_reverse_mixing_load_skip: | |
SUBS R8, R8, #1 | |
BGT C_uncompressed_reverse_mixing_loop | |
ADD R3, R3, #2 | |
B C_end_mixing | |
/* | |
* This is the main BDPCM Decoder | |
* It decodes and caches a block of PCM data | |
* and returns them in R12 | |
*/ | |
F_bdpcm_decoder: | |
STMFD SP!, {R0, LR} | |
MOV R0, R3, LSR#6 @ clip off everything but the block offset, each block is 0x40 samples long | |
LDR R12, [R4, #CHN_BLOCK_COUNT] | |
CMP R0, R12 | |
BEQ C_bdpcm_decoder_return @ block already decoded -> skip | |
STMFD SP!, {R2, R5-R7} | |
STR R0, [R4, #CHN_BLOCK_COUNT] | |
MOV R12, #0x21 @ 1 Block = 0x21 Bytes, 0x40 decoded samples | |
MUL R2, R12, R0 | |
LDR R12, [R4, #CHN_WAVE_OFFSET] | |
ADD R2, R2, R12 @ calc block ROM position | |
ADD R2, R2, #0x10 | |
LDR R5, decoder_buffer | |
ADR R6, delta_lookup_table | |
MOV R7, #0x40 @ 1 block = 0x40 samples | |
LDRB LR, [R2], #1 | |
STRB LR, [R5], #1 | |
LDRB R12, [R2], #1 | |
B C_bdpcm_decoder_lsb | |
C_bdpcm_decoder_msb: | |
LDRB R12, [R2], #1 | |
MOV R0, R12, LSR#4 | |
LDRSB R0, [R6, R0] | |
ADD LR, LR, R0 | |
STRB LR, [R5], #1 | |
C_bdpcm_decoder_lsb: | |
AND R0, R12, #0xF | |
LDRSB R0, [R6, R0] | |
ADD LR, LR, R0 | |
STRB LR, [R5], #1 | |
SUBS R7, R7, #2 | |
BGT C_bdpcm_decoder_msb | |
LDMFD SP!, {R2, R5-R7} | |
C_bdpcm_decoder_return: | |
LDR R12, decoder_buffer | |
AND R0, R3, #0x3F | |
LDRSB R12, [R12, R0] | |
LDMFD SP!, {R0, PC} | |
.align 2 | |
decoder_buffer: | |
.word gUnknown_03001300 | |
delta_lookup_table: | |
.byte 0x0, 0x1, 0x4, 0x9, 0x10, 0x19, 0x24, 0x31, 0xC0, 0xCF, 0xDC, 0xE7, 0xF0, 0xF7, 0xFC, 0xFF | |
.endif /* ENABLE_DECOMPRESSION*/ | |
main_mixer_end: | |
.syntax unified | |
thumb_func_start SoundMainBTM | |
SoundMainBTM: | |
mov r12, r4 | |
movs r1, 0 | |
movs r2, 0 | |
movs r3, 0 | |
movs r4, 0 | |
stm r0!, {r1-r4} | |
stm r0!, {r1-r4} | |
stm r0!, {r1-r4} | |
stm r0!, {r1-r4} | |
mov r4, r12 | |
bx lr | |
thumb_func_end SoundMainBTM | |
thumb_func_start RealClearChain | |
RealClearChain: | |
ldr r3, [r0, 0x2C] | |
cmp r3, 0 | |
beq _081DD5E2 | |
ldr r1, [r0, 0x34] | |
ldr r2, [r0, 0x30] | |
cmp r2, 0 | |
beq _081DD5D6 | |
str r1, [r2, 0x34] | |
b _081DD5D8 | |
_081DD5D6: | |
str r1, [r3, 0x20] | |
_081DD5D8: | |
cmp r1, 0 | |
beq _081DD5DE | |
str r2, [r1, 0x30] | |
_081DD5DE: | |
movs r1, 0 | |
str r1, [r0, 0x2C] | |
_081DD5E2: | |
bx lr | |
thumb_func_end RealClearChain | |
thumb_func_start ply_fine | |
ply_fine: | |
push {r4,r5,lr} | |
adds r5, r1, 0 | |
ldr r4, [r5, o_MusicPlayerTrack_chan] | |
cmp r4, 0 | |
beq ply_fine_done | |
ply_fine_loop: | |
ldrb r1, [r4] | |
movs r0, 0xC7 | |
tst r0, r1 | |
beq ply_fine_ok | |
movs r0, 0x40 | |
orrs r1, r0 | |
strb r1, [r4] | |
ply_fine_ok: | |
adds r0, r4, 0 | |
bl RealClearChain | |
ldr r4, [r4, 0x34] | |
cmp r4, 0 | |
bne ply_fine_loop | |
ply_fine_done: | |
movs r0, 0 | |
strb r0, [r5] | |
pop {r4,r5} | |
pop {r0} | |
bx r0 | |
thumb_func_end ply_fine | |
thumb_func_start MPlayJumpTableCopy | |
MPlayJumpTableCopy: | |
mov r12, lr | |
movs r1, 0x24 | |
ldr r2, lt_MPlayJumpTableTemplate | |
MPlayJumpTableCopy_Loop: | |
ldr r3, [r2] | |
bl chk_adr_r2 | |
stm r0!, {r3} | |
adds r2, 0x4 | |
subs r1, 0x1 | |
bgt MPlayJumpTableCopy_Loop | |
bx r12 | |
thumb_func_end MPlayJumpTableCopy | |
.align 2, 0 | |
.thumb_func | |
ldrb_r3_r2: | |
ldrb r3, [r2] | |
@ This attempts to protect against reading anything from the BIOS ROM | |
@ besides the jump table template. | |
@ It assumes that the jump table template is located at the end of the ROM. | |
.thumb_func | |
chk_adr_r2: | |
push {r0} | |
lsrs r0, r2, 25 | |
bne chk_adr_r2_done @ if adr >= 0x2000000 (i.e. not in BIOS ROM), accept it | |
ldr r0, lt_MPlayJumpTableTemplate | |
cmp r2, r0 | |
blo chk_adr_r2_reject @ if adr < gMPlayJumpTableTemplate, reject it | |
lsrs r0, r2, 14 | |
beq chk_adr_r2_done @ if adr < 0x40000 (i.e. in BIOS ROM), accept it | |
chk_adr_r2_reject: | |
movs r3, 0 | |
chk_adr_r2_done: | |
pop {r0} | |
bx lr | |
.align 2, 0 | |
lt_MPlayJumpTableTemplate: .word gMPlayJumpTableTemplate | |
thumb_func_start ld_r3_tp_adr_i | |
ld_r3_tp_adr_i: | |
ldr r2, [r1, 0x40] | |
_081DD64A: | |
adds r3, r2, 0x1 | |
str r3, [r1, 0x40] | |
ldrb r3, [r2] | |
b chk_adr_r2 | |
thumb_func_end ld_r3_tp_adr_i | |
thumb_func_start ply_goto | |
ply_goto: | |
push {lr} | |
ply_goto_1: | |
ldr r2, [r1, o_MusicPlayerTrack_cmdPtr] | |
ldrb r0, [r2, 0x3] | |
lsls r0, 8 | |
ldrb r3, [r2, 0x2] | |
orrs r0, r3 | |
lsls r0, 8 | |
ldrb r3, [r2, 0x1] | |
orrs r0, r3 | |
lsls r0, 8 | |
bl ldrb_r3_r2 | |
orrs r0, r3 | |
str r0, [r1, o_MusicPlayerTrack_cmdPtr] | |
pop {r0} | |
bx r0 | |
thumb_func_end ply_goto | |
thumb_func_start ply_patt | |
ply_patt: | |
ldrb r2, [r1, o_MusicPlayerTrack_patternLevel] | |
cmp r2, 3 | |
bhs ply_patt_done | |
lsls r2, 2 | |
adds r3, r1, r2 | |
ldr r2, [r1, o_MusicPlayerTrack_cmdPtr] | |
adds r2, 0x4 | |
str r2, [r3, o_MusicPlayerTrack_patternStack] | |
ldrb r2, [r1, o_MusicPlayerTrack_patternLevel] | |
adds r2, 1 | |
strb r2, [r1, o_MusicPlayerTrack_patternLevel] | |
b ply_goto | |
ply_patt_done: | |
b ply_fine | |
thumb_func_end ply_patt | |
thumb_func_start ply_pend | |
ply_pend: | |
ldrb r2, [r1, o_MusicPlayerTrack_patternLevel] | |
cmp r2, 0 | |
beq ply_pend_done | |
subs r2, 1 | |
strb r2, [r1, o_MusicPlayerTrack_patternLevel] | |
lsls r2, 2 | |
adds r3, r1, r2 | |
ldr r2, [r3, o_MusicPlayerTrack_patternStack] | |
str r2, [r1, o_MusicPlayerTrack_cmdPtr] | |
ply_pend_done: | |
bx lr | |
thumb_func_end ply_pend | |
thumb_func_start ply_rept | |
ply_rept: | |
push {lr} | |
ldr r2, [r1, o_MusicPlayerTrack_cmdPtr] | |
ldrb r3, [r2] | |
cmp r3, 0 | |
bne ply_rept_1 | |
adds r2, 1 | |
str r2, [r1, o_MusicPlayerTrack_cmdPtr] | |
b ply_goto_1 | |
ply_rept_1: | |
ldrb r3, [r1, o_MusicPlayerTrack_repN] | |
adds r3, 1 | |
strb r3, [r1, o_MusicPlayerTrack_repN] | |
mov r12, r3 | |
bl ld_r3_tp_adr_i | |
cmp r12, r3 | |
bhs ply_rept_2 | |
b ply_goto_1 | |
ply_rept_2: | |
movs r3, 0 | |
strb r3, [r1, o_MusicPlayerTrack_repN] | |
adds r2, 5 | |
str r2, [r1, o_MusicPlayerTrack_cmdPtr] | |
pop {r0} | |
bx r0 | |
thumb_func_end ply_rept | |
thumb_func_start ply_prio | |
ply_prio: | |
mov r12, lr | |
bl ld_r3_tp_adr_i | |
strb r3, [r1, o_MusicPlayerTrack_priority] | |
bx r12 | |
thumb_func_end ply_prio | |
thumb_func_start ply_tempo | |
ply_tempo: | |
mov r12, lr | |
bl ld_r3_tp_adr_i | |
lsls r3, 1 | |
strh r3, [r0, o_MusicPlayerInfo_tempoD] | |
ldrh r2, [r0, o_MusicPlayerInfo_tempoU] | |
muls r3, r2 | |
lsrs r3, 8 | |
strh r3, [r0, o_MusicPlayerInfo_tempoI] | |
bx r12 | |
thumb_func_end ply_tempo | |
thumb_func_start ply_keysh | |
ply_keysh: | |
mov r12, lr | |
bl ld_r3_tp_adr_i | |
strb r3, [r1, o_MusicPlayerTrack_keyShift] | |
ldrb r3, [r1, o_MusicPlayerTrack_flags] | |
movs r2, 0xC | |
orrs r3, r2 | |
strb r3, [r1, o_MusicPlayerTrack_flags] | |
bx r12 | |
thumb_func_end ply_keysh | |
thumb_func_start ply_voice | |
ply_voice: | |
mov r12, lr | |
ldr r2, [r1, o_MusicPlayerTrack_cmdPtr] | |
ldrb r3, [r2] | |
adds r2, 1 | |
str r2, [r1, o_MusicPlayerTrack_cmdPtr] | |
lsls r2, r3, 1 | |
adds r2, r3 | |
lsls r2, 2 | |
ldr r3, [r0, o_MusicPlayerInfo_tone] | |
adds r2, r3 | |
ldr r3, [r2] | |
bl chk_adr_r2 | |
str r3, [r1, o_MusicPlayerTrack_ToneData_type] | |
ldr r3, [r2, 0x4] | |
bl chk_adr_r2 | |
str r3, [r1, o_MusicPlayerTrack_ToneData_wav] | |
ldr r3, [r2, 0x8] | |
bl chk_adr_r2 | |
str r3, [r1, o_MusicPlayerTrack_ToneData_attack] | |
bx r12 | |
thumb_func_end ply_voice | |
thumb_func_start ply_vol | |
ply_vol: | |
mov r12, lr | |
bl ld_r3_tp_adr_i | |
strb r3, [r1, o_MusicPlayerTrack_vol] | |
ldrb r3, [r1, o_MusicPlayerTrack_flags] | |
movs r2, 0x3 | |
orrs r3, r2 | |
strb r3, [r1, o_MusicPlayerTrack_flags] | |
bx r12 | |
thumb_func_end ply_vol | |
thumb_func_start ply_pan | |
ply_pan: | |
mov r12, lr | |
bl ld_r3_tp_adr_i | |
subs r3, 0x40 | |
strb r3, [r1, o_MusicPlayerTrack_pan] | |
ldrb r3, [r1, o_MusicPlayerTrack_flags] | |
movs r2, 0x3 | |
orrs r3, r2 | |
strb r3, [r1, o_MusicPlayerTrack_flags] | |
bx r12 | |
thumb_func_end ply_pan | |
thumb_func_start ply_bend | |
ply_bend: | |
mov r12, lr | |
bl ld_r3_tp_adr_i | |
subs r3, 0x40 | |
strb r3, [r1, o_MusicPlayerTrack_bend] | |
ldrb r3, [r1, o_MusicPlayerTrack_flags] | |
movs r2, 0xC | |
orrs r3, r2 | |
strb r3, [r1, o_MusicPlayerTrack_flags] | |
bx r12 | |
thumb_func_end ply_bend | |
thumb_func_start ply_bendr | |
ply_bendr: | |
mov r12, lr | |
bl ld_r3_tp_adr_i | |
strb r3, [r1, o_MusicPlayerTrack_bendRange] | |
ldrb r3, [r1, o_MusicPlayerTrack_flags] | |
movs r2, 0xC | |
orrs r3, r2 | |
strb r3, [r1, o_MusicPlayerTrack_flags] | |
bx r12 | |
thumb_func_end ply_bendr | |
thumb_func_start ply_lfodl | |
ply_lfodl: | |
mov r12, lr | |
bl ld_r3_tp_adr_i | |
strb r3, [r1, o_MusicPlayerTrack_lfoDelay] | |
bx r12 | |
thumb_func_end ply_lfodl | |
thumb_func_start ply_modt | |
ply_modt: | |
mov r12, lr | |
bl ld_r3_tp_adr_i | |
ldrb r0, [r1, o_MusicPlayerTrack_modT] | |
cmp r0, r3 | |
beq _081DD7AA | |
strb r3, [r1, o_MusicPlayerTrack_modT] | |
ldrb r3, [r1, o_MusicPlayerTrack_flags] | |
movs r2, 0xF | |
orrs r3, r2 | |
strb r3, [r1, o_MusicPlayerTrack_flags] | |
_081DD7AA: | |
bx r12 | |
thumb_func_end ply_modt | |
thumb_func_start ply_tune | |
ply_tune: | |
mov r12, lr | |
bl ld_r3_tp_adr_i | |
subs r3, 0x40 | |
strb r3, [r1, o_MusicPlayerTrack_tune] | |
ldrb r3, [r1, o_MusicPlayerTrack_flags] | |
movs r2, 0xC | |
orrs r3, r2 | |
strb r3, [r1, o_MusicPlayerTrack_flags] | |
bx r12 | |
thumb_func_end ply_tune | |
thumb_func_start ply_port | |
ply_port: | |
mov r12, lr | |
ldr r2, [r1, o_MusicPlayerTrack_cmdPtr] | |
ldrb r3, [r2] | |
adds r2, 1 | |
ldr r0, =REG_SOUND1CNT_L @ sound register base address | |
adds r0, r3 | |
bl _081DD64A | |
strb r3, [r0] | |
bx r12 | |
.pool | |
thumb_func_end ply_port | |
thumb_func_start m4aSoundVSync | |
m4aSoundVSync: | |
ldr r0, lt2_SOUND_INFO_PTR | |
ldr r0, [r0] | |
@ Exit the function if ident is not ID_NUMBER or ID_NUMBER+1. | |
ldr r2, lt2_ID_NUMBER | |
ldr r3, [r0, o_SoundInfo_ident] | |
subs r3, r2 | |
cmp r3, 1 | |
bhi m4aSoundVSync_Done | |
@ Decrement the PCM DMA counter. If it reaches 0, we need to do a DMA. | |
ldrb r1, [r0, o_SoundInfo_pcmDmaCounter] | |
subs r1, 1 | |
strb r1, [r0, o_SoundInfo_pcmDmaCounter] | |
bgt m4aSoundVSync_Done | |
@ Reload the PCM DMA counter. | |
ldrb r1, [r0, o_SoundInfo_pcmDmaPeriod] | |
strb r1, [r0, o_SoundInfo_pcmDmaCounter] | |
ldr r2, =REG_DMA1 | |
ldr r1, [r2, 0x8] @ DMA1CNT | |
lsls r1, 7 | |
bcc m4aSoundVSync_SkipDMA1 @ branch if repeat bit isn't set | |
ldr r1, =((DMA_ENABLE | DMA_START_NOW | DMA_32BIT | DMA_SRC_INC | DMA_DEST_FIXED) << 16) | 4 | |
str r1, [r2, 0x8] @ DMA1CNT | |
m4aSoundVSync_SkipDMA1: | |
ldr r1, [r2, 0xC + 0x8] @ DMA2CNT | |
lsls r1, 7 | |
bcc m4aSoundVSync_SkipDMA2 @ branch if repeat bit isn't set | |
ldr r1, =((DMA_ENABLE | DMA_START_NOW | DMA_32BIT | DMA_SRC_INC | DMA_DEST_FIXED) << 16) | 4 | |
str r1, [r2, 0xC + 0x8] @ DMA2CNT | |
m4aSoundVSync_SkipDMA2: | |
@ turn off DMA1/DMA2 | |
movs r1, DMA_32BIT >> 8 | |
lsls r1, 8 | |
strh r1, [r2, 0xA] @ DMA1CNT_H | |
strh r1, [r2, 0xC + 0xA] @ DMA2CNT_H | |
@ turn on DMA1/DMA2 direct-sound FIFO mode | |
movs r1, (DMA_ENABLE | DMA_START_SPECIAL | DMA_32BIT | DMA_REPEAT) >> 8 | |
lsls r1, 8 @ LSB is 0, so DMA_SRC_INC is used (destination is always fixed in FIFO mode) | |
strh r1, [r2, 0xA] @ DMA1CNT_H | |
strh r1, [r2, 0xC + 0xA] @ DMA2CNT_H | |
m4aSoundVSync_Done: | |
bx lr | |
.pool | |
thumb_func_end m4aSoundVSync | |
thumb_func_start MPlayMain | |
MPlayMain: | |
ldr r2, lt2_ID_NUMBER | |
ldr r3, [r0, o_MusicPlayerInfo_ident] | |
cmp r2, r3 | |
beq _081DD82E | |
bx lr | |
_081DD82E: | |
adds r3, 0x1 | |
str r3, [r0, o_MusicPlayerInfo_ident] | |
push {r0,lr} | |
ldr r3, [r0, o_MusicPlayerInfo_func] | |
cmp r3, 0 | |
beq _081DD840 | |
ldr r0, [r0, o_MusicPlayerInfo_intp] | |
bl call_r3 | |
_081DD840: | |
pop {r0} | |
push {r4-r7} | |
mov r4, r8 | |
mov r5, r9 | |
mov r6, r10 | |
mov r7, r11 | |
push {r4-r7} | |
adds r7, r0, 0 | |
ldr r0, [r7, o_MusicPlayerInfo_status] | |
cmp r0, 0 | |
bge _081DD858 | |
b _081DDA6C | |
_081DD858: | |
ldr r0, lt2_SOUND_INFO_PTR | |
ldr r0, [r0] | |
mov r8, r0 | |
adds r0, r7, 0 | |
bl FadeOutBody | |
ldr r0, [r7, o_MusicPlayerInfo_status] | |
cmp r0, 0 | |
bge _081DD86C | |
b _081DDA6C | |
_081DD86C: | |
ldrh r0, [r7, o_MusicPlayerInfo_tempoC] | |
ldrh r1, [r7, o_MusicPlayerInfo_tempoI] | |
adds r0, r1 | |
b _081DD9BC | |
_081DD874: | |
ldrb r6, [r7, o_MusicPlayerInfo_trackCount] | |
ldr r5, [r7, o_MusicPlayerInfo_tracks] | |
movs r3, 0x1 | |
movs r4, 0 | |
_081DD87C: | |
ldrb r0, [r5] | |
movs r1, 0x80 | |
tst r1, r0 | |
bne _081DD886 | |
b _081DD998 | |
_081DD886: | |
mov r10, r3 | |
orrs r4, r3 | |
mov r11, r4 | |
ldr r4, [r5, o_MusicPlayerTrack_chan] | |
cmp r4, 0 | |
beq _081DD8BA | |
_081DD892: | |
ldrb r1, [r4] | |
movs r0, 0xC7 | |
tst r0, r1 | |
beq _081DD8AE | |
ldrb r0, [r4, 0x10] | |
cmp r0, 0 | |
beq _081DD8B4 | |
subs r0, 0x1 | |
strb r0, [r4, 0x10] | |
bne _081DD8B4 | |
movs r0, 0x40 | |
orrs r1, r0 | |
strb r1, [r4] | |
b _081DD8B4 | |
_081DD8AE: | |
adds r0, r4, 0 | |
bl ClearChain | |
_081DD8B4: | |
ldr r4, [r4, 0x34] | |
cmp r4, 0 | |
bne _081DD892 | |
_081DD8BA: | |
ldrb r3, [r5, o_MusicPlayerTrack_flags] | |
movs r0, 0x40 | |
tst r0, r3 | |
beq _081DD938 | |
adds r0, r5, 0 | |
bl Clear64byte | |
movs r0, 0x80 | |
strb r0, [r5] | |
movs r0, 0x2 | |
strb r0, [r5, o_MusicPlayerTrack_bendRange] | |
movs r0, 0x40 | |
strb r0, [r5, o_MusicPlayerTrack_volX] | |
movs r0, 0x16 | |
strb r0, [r5, o_MusicPlayerTrack_lfoSpeed] | |
movs r0, 0x1 | |
adds r1, r5, 0x6 | |
strb r0, [r1, o_MusicPlayerTrack_ToneData_type - 0x6] | |
b _081DD938 | |
_081DD8E0: | |
ldr r2, [r5, o_MusicPlayerTrack_cmdPtr] | |
ldrb r1, [r2] | |
cmp r1, 0x80 | |
bhs _081DD8EC | |
ldrb r1, [r5, o_MusicPlayerTrack_runningStatus] | |
b _081DD8F6 | |
_081DD8EC: | |
adds r2, 0x1 | |
str r2, [r5, o_MusicPlayerTrack_cmdPtr] | |
cmp r1, 0xBD | |
bcc _081DD8F6 | |
strb r1, [r5, o_MusicPlayerTrack_runningStatus] | |
_081DD8F6: | |
cmp r1, 0xCF | |
bcc _081DD90C | |
mov r0, r8 | |
ldr r3, [r0, o_SoundInfo_plynote] | |
adds r0, r1, 0 | |
subs r0, 0xCF | |
adds r1, r7, 0 | |
adds r2, r5, 0 | |
bl call_r3 | |
b _081DD938 | |
_081DD90C: | |
cmp r1, 0xB0 | |
bls _081DD92E | |
adds r0, r1, 0 | |
subs r0, 0xB1 | |
strb r0, [r7, o_MusicPlayerInfo_cmd] | |
mov r3, r8 | |
ldr r3, [r3, o_SoundInfo_MPlayJumpTable] | |
lsls r0, 2 | |
ldr r3, [r3, r0] | |
adds r0, r7, 0 | |
adds r1, r5, 0 | |
bl call_r3 | |
ldrb r0, [r5, o_MusicPlayerTrack_flags] | |
cmp r0, 0 | |
beq _081DD994 | |
b _081DD938 | |
_081DD92E: | |
ldr r0, lt_gClockTable | |
subs r1, 0x80 | |
adds r1, r0 | |
ldrb r0, [r1] | |
strb r0, [r5, o_MusicPlayerTrack_wait] | |
_081DD938: | |
ldrb r0, [r5, o_MusicPlayerTrack_wait] | |
cmp r0, 0 | |
beq _081DD8E0 | |
subs r0, 0x1 | |
strb r0, [r5, o_MusicPlayerTrack_wait] | |
ldrb r1, [r5, o_MusicPlayerTrack_lfoSpeed] | |
cmp r1, 0 | |
beq _081DD994 | |
ldrb r0, [r5, o_MusicPlayerTrack_mod] | |
cmp r0, 0 | |
beq _081DD994 | |
ldrb r0, [r5, o_MusicPlayerTrack_lfoDelayC] | |
cmp r0, 0 | |
beq _081DD95A | |
subs r0, 0x1 | |
strb r0, [r5, o_MusicPlayerTrack_lfoDelayC] | |
b _081DD994 | |
_081DD95A: | |
ldrb r0, [r5, o_MusicPlayerTrack_lfoSpeedC] | |
adds r0, r1 | |
strb r0, [r5, o_MusicPlayerTrack_lfoSpeedC] | |
adds r1, r0, 0 | |
subs r0, 0x40 | |
lsls r0, 24 | |
bpl _081DD96E | |
lsls r2, r1, 24 | |
asrs r2, 24 | |
b _081DD972 | |
_081DD96E: | |
movs r0, 0x80 | |
subs r2, r0, r1 | |
_081DD972: | |
ldrb r0, [r5, o_MusicPlayerTrack_mod] | |
muls r0, r2 | |
asrs r2, r0, 6 | |
ldrb r0, [r5, o_MusicPlayerTrack_modM] | |
eors r0, r2 | |
lsls r0, 24 | |
beq _081DD994 | |
strb r2, [r5, o_MusicPlayerTrack_modM] | |
ldrb r0, [r5] | |
ldrb r1, [r5, o_MusicPlayerTrack_modT] | |
cmp r1, 0 | |
bne _081DD98E | |
movs r1, 0xC | |
b _081DD990 | |
_081DD98E: | |
movs r1, 0x3 | |
_081DD990: | |
orrs r0, r1 | |
strb r0, [r5, o_MusicPlayerTrack_flags] | |
_081DD994: | |
mov r3, r10 | |
mov r4, r11 | |
_081DD998: | |
subs r6, 0x1 | |
ble _081DD9A4 | |
movs r0, 0x50 | |
adds r5, r0 | |
lsls r3, 1 | |
b _081DD87C | |
_081DD9A4: | |
ldr r0, [r7, o_MusicPlayerInfo_clock] | |
adds r0, 0x1 | |
str r0, [r7, o_MusicPlayerInfo_clock] | |
cmp r4, 0 | |
bne _081DD9B6 | |
movs r0, 0x80 | |
lsls r0, 24 | |
str r0, [r7, o_MusicPlayerInfo_status] | |
b _081DDA6C | |
_081DD9B6: | |
str r4, [r7, o_MusicPlayerInfo_status] | |
ldrh r0, [r7, o_MusicPlayerInfo_tempoC] | |
subs r0, 0x96 | |
_081DD9BC: | |
strh r0, [r7, o_MusicPlayerInfo_tempoC] | |
cmp r0, 0x96 | |
bcc _081DD9C4 | |
b _081DD874 | |
_081DD9C4: | |
ldrb r2, [r7, o_MusicPlayerInfo_trackCount] | |
ldr r5, [r7, o_MusicPlayerInfo_tracks] | |
_081DD9C8: | |
ldrb r0, [r5, o_MusicPlayerTrack_flags] | |
movs r1, 0x80 | |
tst r1, r0 | |
beq _081DDA62 | |
movs r1, 0xF | |
tst r1, r0 | |
beq _081DDA62 | |
mov r9, r2 | |
adds r0, r7, 0 | |
adds r1, r5, 0 | |
bl TrkVolPitSet | |
ldr r4, [r5, o_MusicPlayerTrack_chan] | |
cmp r4, 0 | |
beq _081DDA58 | |
_081DD9E6: | |
ldrb r1, [r4, o_SoundChannel_status] | |
movs r0, 0xC7 | |
tst r0, r1 | |
bne _081DD9F6 | |
adds r0, r4, 0 | |
bl ClearChain | |
b _081DDA52 | |
_081DD9F6: | |
ldrb r0, [r4, o_SoundChannel_type] | |
movs r6, 0x7 | |
ands r6, r0 | |
ldrb r3, [r5, o_MusicPlayerTrack_flags] | |
movs r0, 0x3 | |
tst r0, r3 | |
beq _081DDA14 | |
bl ChnVolSetAsm | |
cmp r6, 0 | |
beq _081DDA14 | |
ldrb r0, [r4, o_CgbChannel_mo] | |
movs r1, 0x1 | |
orrs r0, r1 | |
strb r0, [r4, o_CgbChannel_mo] | |
_081DDA14: | |
ldrb r3, [r5, o_MusicPlayerTrack_flags] | |
movs r0, 0xC | |
tst r0, r3 | |
beq _081DDA52 | |
ldrb r1, [r4, o_SoundChannel_ky] | |
movs r0, 0x8 | |
ldrsb r0, [r5, r0] | |
adds r2, r1, r0 | |
bpl _081DDA28 | |
movs r2, 0 | |
_081DDA28: | |
cmp r6, 0 | |
beq _081DDA46 | |
mov r0, r8 | |
ldr r3, [r0, o_SoundInfo_MidiKeyToCgbFreq] | |
adds r1, r2, 0 | |
ldrb r2, [r5, o_MusicPlayerTrack_pitM] | |
adds r0, r6, 0 | |
bl call_r3 | |
str r0, [r4, o_CgbChannel_fr] | |
ldrb r0, [r4, o_CgbChannel_mo] | |
movs r1, 0x2 | |
orrs r0, r1 | |
strb r0, [r4, o_CgbChannel_mo] | |
b _081DDA52 | |
_081DDA46: | |
adds r1, r2, 0 | |
ldrb r2, [r5, o_MusicPlayerTrack_pitM] | |
ldr r0, [r4, o_SoundChannel_wav] | |
bl MidiKeyToFreq | |
str r0, [r4, o_SoundChannel_freq] | |
_081DDA52: | |
ldr r4, [r4, o_SoundChannel_np] | |
cmp r4, 0 | |
bne _081DD9E6 | |
_081DDA58: | |
ldrb r0, [r5, o_MusicPlayerTrack_flags] | |
movs r1, 0xF0 | |
ands r0, r1 | |
strb r0, [r5, o_MusicPlayerTrack_flags] | |
mov r2, r9 | |
_081DDA62: | |
subs r2, 0x1 | |
ble _081DDA6C | |
movs r0, 0x50 | |
adds r5, r0 | |
bgt _081DD9C8 | |
_081DDA6C: | |
ldr r0, lt2_ID_NUMBER | |
str r0, [r7, o_MusicPlayerInfo_ident] | |
pop {r0-r7} | |
mov r8, r0 | |
mov r9, r1 | |
mov r10, r2 | |
mov r11, r3 | |
pop {r3} | |
call_r3: | |
bx r3 | |
.align 2, 0 | |
lt_gClockTable: .word gClockTable | |
lt2_SOUND_INFO_PTR: .word SOUND_INFO_PTR | |
lt2_ID_NUMBER: .word ID_NUMBER | |
thumb_func_end MPlayMain | |
thumb_func_start TrackStop | |
TrackStop: | |
push {r4-r6,lr} | |
adds r5, r1, 0 | |
ldrb r1, [r5, o_MusicPlayerTrack_flags] | |
movs r0, 0x80 | |
tst r0, r1 | |
beq TrackStop_Done | |
ldr r4, [r5, o_MusicPlayerTrack_chan] | |
cmp r4, 0 | |
beq TrackStop_3 | |
movs r6, 0 | |
TrackStop_Loop: | |
ldrb r0, [r4, o_SoundChannel_status] | |
cmp r0, 0 | |
beq TrackStop_2 | |
ldrb r0, [r4, o_SoundChannel_type] | |
movs r3, 0x7 | |
ands r0, r3 | |
beq TrackStop_1 | |
ldr r3, =SOUND_INFO_PTR | |
ldr r3, [r3] | |
ldr r3, [r3, o_SoundInfo_CgbOscOff] | |
bl call_r3 | |
TrackStop_1: | |
strb r6, [r4, o_SoundChannel_status] | |
TrackStop_2: | |
str r6, [r4, o_SoundChannel_track] | |
ldr r4, [r4, o_SoundChannel_np] | |
cmp r4, 0 | |
bne TrackStop_Loop | |
TrackStop_3: | |
str r4, [r5, o_MusicPlayerTrack_chan] | |
TrackStop_Done: | |
pop {r4-r6} | |
pop {r0} | |
bx r0 | |
.pool | |
thumb_func_end TrackStop | |
thumb_func_start ChnVolSetAsm | |
ChnVolSetAsm: | |
ldrb r1, [r4, 0x12] | |
movs r0, 0x14 | |
ldrsb r2, [r4, r0] | |
movs r3, 0x80 | |
adds r3, r2 | |
muls r3, r1 | |
ldrb r0, [r5, 0x10] | |
muls r0, r3 | |
asrs r0, 14 | |
cmp r0, 0xFF | |
bls _081DDAE8 | |
movs r0, 0xFF | |
_081DDAE8: | |
strb r0, [r4, 0x2] | |
movs r3, 0x7F | |
subs r3, r2 | |
muls r3, r1 | |
ldrb r0, [r5, 0x11] | |
muls r0, r3 | |
asrs r0, 14 | |
cmp r0, 0xFF | |
bls _081DDAFC | |
movs r0, 0xFF | |
_081DDAFC: | |
strb r0, [r4, 0x3] | |
bx lr | |
thumb_func_end ChnVolSetAsm | |
thumb_func_start ply_note | |
ply_note: | |
push {r4-r7,lr} | |
mov r4, r8 | |
mov r5, r9 | |
mov r6, r10 | |
mov r7, r11 | |
push {r4-r7} | |
sub sp, 0x18 | |
str r1, [sp] | |
adds r5, r2, 0 | |
ldr r1, =SOUND_INFO_PTR | |
ldr r1, [r1] | |
str r1, [sp, 0x4] | |
ldr r1, =gClockTable | |
adds r0, r1 | |
ldrb r0, [r0] | |
strb r0, [r5, o_MusicPlayerTrack_gateTime] | |
ldr r3, [r5, o_MusicPlayerTrack_cmdPtr] | |
ldrb r0, [r3] | |
cmp r0, 0x80 | |
bhs _081DDB46 | |
strb r0, [r5, o_MusicPlayerTrack_key] | |
adds r3, 0x1 | |
ldrb r0, [r3] | |
cmp r0, 0x80 | |
bhs _081DDB44 | |
strb r0, [r5, o_MusicPlayerTrack_velocity] | |
adds r3, 0x1 | |
ldrb r0, [r3] | |
cmp r0, 0x80 | |
bhs _081DDB44 | |
ldrb r1, [r5, o_MusicPlayerTrack_gateTime] | |
adds r1, r0 | |
strb r1, [r5, o_MusicPlayerTrack_gateTime] | |
adds r3, 0x1 | |
_081DDB44: | |
str r3, [r5, o_MusicPlayerTrack_cmdPtr] | |
_081DDB46: | |
movs r0, 0 | |
str r0, [sp, 0x14] | |
adds r4, r5, 0 | |
adds r4, o_MusicPlayerTrack_ToneData_type | |
ldrb r2, [r4] | |
movs r0, TONEDATA_TYPE_RHY | TONEDATA_TYPE_SPL | |
tst r0, r2 | |
beq _081DDB98 | |
ldrb r3, [r5, o_MusicPlayerTrack_key] | |
movs r0, TONEDATA_TYPE_SPL | |
tst r0, r2 | |
beq _081DDB66 | |
ldr r1, [r5, o_MusicPlayerTrack_ToneData_keySplitTable] | |
adds r1, r3 | |
ldrb r0, [r1] | |
b _081DDB68 | |
_081DDB66: | |
adds r0, r3, 0 | |
_081DDB68: | |
lsls r1, r0, 1 | |
adds r1, r0 | |
lsls r1, 2 | |
ldr r0, [r5, o_MusicPlayerTrack_ToneData_wav] | |
adds r1, r0 | |
mov r9, r1 | |
mov r6, r9 | |
ldrb r1, [r6] | |
movs r0, 0xC0 | |
tst r0, r1 | |
beq _081DDB80 | |
b _081DDCEA | |
_081DDB80: | |
movs r0, 0x80 | |
tst r0, r2 | |
beq _081DDB9C | |
ldrb r1, [r6, 0x3] | |
movs r0, 0x80 | |
tst r0, r1 | |
beq _081DDB94 | |
subs r1, 0xC0 | |
lsls r1, 1 | |
str r1, [sp, 0x14] | |
_081DDB94: | |
ldrb r3, [r6, 0x1] | |
b _081DDB9C | |
_081DDB98: | |
mov r9, r4 | |
ldrb r3, [r5, 0x5] | |
_081DDB9C: | |
str r3, [sp, 0x8] | |
ldr r6, [sp] | |
ldrb r1, [r6, 0x9] | |
ldrb r0, [r5, 0x1D] | |
adds r0, r1 | |
cmp r0, 0xFF | |
bls _081DDBAC | |
movs r0, 0xFF | |
_081DDBAC: | |
str r0, [sp, 0x10] | |
mov r6, r9 | |
ldrb r0, [r6] | |
movs r6, 0x7 | |
ands r6, r0 | |
str r6, [sp, 0xC] | |
beq _081DDBEC | |
ldr r0, [sp, 0x4] | |
ldr r4, [r0, 0x1C] | |
cmp r4, 0 | |
bne _081DDBC4 | |
b _081DDCEA | |
_081DDBC4: | |
subs r6, 0x1 | |
lsls r0, r6, 6 | |
adds r4, r0 | |
ldrb r1, [r4] | |
movs r0, 0xC7 | |
tst r0, r1 | |
beq _081DDC40 | |
movs r0, 0x40 | |
tst r0, r1 | |
bne _081DDC40 | |
ldrb r1, [r4, 0x13] | |
ldr r0, [sp, 0x10] | |
cmp r1, r0 | |
bcc _081DDC40 | |
beq _081DDBE4 | |
b _081DDCEA | |
_081DDBE4: | |
ldr r0, [r4, 0x2C] | |
cmp r0, r5 | |
bcs _081DDC40 | |
b _081DDCEA | |
_081DDBEC: | |
ldr r6, [sp, 0x10] | |
adds r7, r5, 0 | |
movs r2, 0 | |
mov r8, r2 | |
ldr r4, [sp, 0x4] | |
ldrb r3, [r4, 0x6] | |
adds r4, 0x50 | |
_081DDBFA: | |
ldrb r1, [r4] | |
movs r0, 0xC7 | |
tst r0, r1 | |
beq _081DDC40 | |
movs r0, 0x40 | |
tst r0, r1 | |
beq _081DDC14 | |
cmp r2, 0 | |
bne _081DDC18 | |
adds r2, 0x1 | |
ldrb r6, [r4, 0x13] | |
ldr r7, [r4, 0x2C] | |
b _081DDC32 | |
_081DDC14: | |
cmp r2, 0 | |
bne _081DDC34 | |
_081DDC18: | |
ldrb r0, [r4, 0x13] | |
cmp r0, r6 | |
bcs _081DDC24 | |
adds r6, r0, 0 | |
ldr r7, [r4, 0x2C] | |
b _081DDC32 | |
_081DDC24: | |
bhi _081DDC34 | |
ldr r0, [r4, 0x2C] | |
cmp r0, r7 | |
bls _081DDC30 | |
adds r7, r0, 0 | |
b _081DDC32 | |
_081DDC30: | |
bcc _081DDC34 | |
_081DDC32: | |
mov r8, r4 | |
_081DDC34: | |
adds r4, 0x40 | |
subs r3, 0x1 | |
bgt _081DDBFA | |
mov r4, r8 | |
cmp r4, 0 | |
beq _081DDCEA | |
_081DDC40: | |
adds r0, r4, 0 | |
bl ClearChain | |
movs r1, 0 | |
str r1, [r4, 0x30] | |
ldr r3, [r5, 0x20] | |
str r3, [r4, 0x34] | |
cmp r3, 0 | |
beq _081DDC54 | |
str r4, [r3, 0x30] | |
_081DDC54: | |
str r4, [r5, 0x20] | |
str r5, [r4, 0x2C] | |
ldrb r0, [r5, 0x1B] | |
strb r0, [r5, 0x1C] | |
cmp r0, r1 | |
beq _081DDC66 | |
adds r1, r5, 0 | |
bl clear_modM | |
_081DDC66: | |
ldr r0, [sp] | |
adds r1, r5, 0 | |
bl TrkVolPitSet | |
ldr r0, [r5, 0x4] | |
str r0, [r4, 0x10] | |
ldr r0, [sp, 0x10] | |
strb r0, [r4, 0x13] | |
ldr r0, [sp, 0x8] | |
strb r0, [r4, 0x8] | |
ldr r0, [sp, 0x14] | |
strb r0, [r4, 0x14] | |
mov r6, r9 | |
ldrb r0, [r6] | |
strb r0, [r4, 0x1] | |
ldr r7, [r6, 0x4] | |
str r7, [r4, 0x24] | |
ldr r0, [r6, 0x8] | |
str r0, [r4, 0x4] | |
ldrh r0, [r5, 0x1E] | |
strh r0, [r4, 0xC] | |
bl ChnVolSetAsm | |
ldrb r1, [r4, 0x8] | |
movs r0, 0x8 | |
ldrsb r0, [r5, r0] | |
adds r3, r1, r0 | |
bpl _081DDCA0 | |
movs r3, 0 | |
_081DDCA0: | |
ldr r6, [sp, 0xC] | |
cmp r6, 0 | |
beq _081DDCCE | |
mov r6, r9 | |
ldrb r0, [r6, 0x2] | |
strb r0, [r4, 0x1E] | |
ldrb r1, [r6, 0x3] | |
movs r0, 0x80 | |
tst r0, r1 | |
bne _081DDCBA | |
movs r0, 0x70 | |
tst r0, r1 | |
bne _081DDCBC | |
_081DDCBA: | |
movs r1, 0x8 | |
_081DDCBC: | |
strb r1, [r4, 0x1F] | |
ldrb r2, [r5, 0x9] | |
adds r1, r3, 0 | |
ldr r0, [sp, 0xC] | |
ldr r3, [sp, 0x4] | |
ldr r3, [r3, 0x30] | |
bl call_r3 | |
b _081DDCDC | |
_081DDCCE: | |
ldr r0, [r5, o_MusicPlayerTrack_unk_3C] | |
str r0, [r4, 0x18] | |
ldrb r2, [r5, 0x9] | |
adds r1, r3, 0 | |
adds r0, r7, 0 | |
bl MidiKeyToFreq | |
_081DDCDC: | |
str r0, [r4, 0x20] | |
movs r0, 0x80 | |
strb r0, [r4] | |
ldrb r1, [r5] | |
movs r0, 0xF0 | |
ands r0, r1 | |
strb r0, [r5] | |
_081DDCEA: | |
add sp, 0x18 | |
pop {r0-r7} | |
mov r8, r0 | |
mov r9, r1 | |
mov r10, r2 | |
mov r11, r3 | |
pop {r0} | |
bx r0 | |
.pool | |
thumb_func_end ply_note | |
thumb_func_start ply_endtie | |
ply_endtie: | |
push {r4,r5} | |
ldr r2, [r1, o_MusicPlayerTrack_cmdPtr] | |
ldrb r3, [r2] | |
cmp r3, 0x80 | |
bhs _081DDD16 | |
strb r3, [r1, o_MusicPlayerTrack_key] | |
adds r2, 0x1 | |
str r2, [r1, o_MusicPlayerTrack_cmdPtr] | |
b _081DDD18 | |
_081DDD16: | |
ldrb r3, [r1, o_MusicPlayerTrack_key] | |
_081DDD18: | |
ldr r1, [r1, o_MusicPlayerTrack_chan] | |
cmp r1, 0 | |
beq _081DDD40 | |
movs r4, 0x83 | |
movs r5, 0x40 | |
_081DDD22: | |
ldrb r2, [r1, o_SoundChannel_status] | |
tst r2, r4 | |
beq _081DDD3A | |
tst r2, r5 | |
bne _081DDD3A | |
ldrb r0, [r1, o_SoundChannel_mk] | |
cmp r0, r3 | |
bne _081DDD3A | |
movs r0, 0x40 | |
orrs r2, r0 | |
strb r2, [r1, o_SoundChannel_status] | |
b _081DDD40 | |
_081DDD3A: | |
ldr r1, [r1, o_SoundChannel_np] | |
cmp r1, 0 | |
bne _081DDD22 | |
_081DDD40: | |
pop {r4,r5} | |
bx lr | |
thumb_func_end ply_endtie | |
thumb_func_start clear_modM | |
clear_modM: | |
movs r2, 0 | |
strb r2, [r1, o_MusicPlayerTrack_modM] | |
strb r2, [r1, o_MusicPlayerTrack_lfoSpeedC] | |
ldrb r2, [r1, o_MusicPlayerTrack_modT] | |
cmp r2, 0 | |
bne _081DDD54 | |
movs r2, 0xC | |
b _081DDD56 | |
_081DDD54: | |
movs r2, 0x3 | |
_081DDD56: | |
ldrb r3, [r1, o_MusicPlayerTrack_flags] | |
orrs r3, r2 | |
strb r3, [r1, o_MusicPlayerTrack_flags] | |
bx lr | |
thumb_func_end clear_modM | |
thumb_func_start ld_r3_tp_adr_i | |
ld_r3_tp_adr_i_unchecked: | |
ldr r2, [r1, o_MusicPlayerTrack_cmdPtr] | |
adds r3, r2, 1 | |
str r3, [r1, o_MusicPlayerTrack_cmdPtr] | |
ldrb r3, [r2] | |
bx lr | |
thumb_func_end ld_r3_tp_adr_i | |
thumb_func_start ply_lfos | |
ply_lfos: | |
mov r12, lr | |
bl ld_r3_tp_adr_i_unchecked | |
strb r3, [r1, o_MusicPlayerTrack_lfoSpeed] | |
cmp r3, 0 | |
bne _081DDD7C | |
bl clear_modM | |
_081DDD7C: | |
bx r12 | |
thumb_func_end ply_lfos | |
thumb_func_start ply_mod | |
ply_mod: | |
mov r12, lr | |
bl ld_r3_tp_adr_i_unchecked | |
strb r3, [r1, o_MusicPlayerTrack_mod] | |
cmp r3, 0 | |
bne _081DDD90 | |
bl clear_modM | |
_081DDD90: | |
bx r12 | |
thumb_func_end ply_mod | |
.align 2, 0 @ Don't pad with nop. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment