Decomp the last four DSE track-event handlers in arm9

Decompile from asm:

  DseTrackEvent_WaitUntilFadeout  0x0207199C
  DseTrackEvent_EndTrack          0x020719C8
  DseTrackEvent_SubLoopBegin      0x02071A1C
  DseTrackEvent_SubLoopEnd        0x02071A5C

This empties asm/main_0207199C.s and asm/main_02071A1C.s, so both files and
their .inc are removed rather than split, and the handlers merge into the
adjacent sources added by the previous commit.

EndTrack confirms the second parameter's type, which the previous commit could
only infer from the dispatcher: it writes 1 to the byte at offset 3 of that
argument, which is field_0x0.has_looped in struct dse_sequence. A track that
reaches the end of its main loop setting has_looped is consistent, and no other
struct in dse.h places a byte with that meaning at offset 3.

SubLoopBegin and SubLoopEnd index track->loop_stack, the existing
struct dse_sub_loop[4] at offset 0x24 with a 12-byte stride, which is what the
asm's multiply by 0xc computes.

SubLoopEnd needed two changes past the obvious form. Its index and count locals
are int, not u8: at byte width the compiler inserts and rX, rX, #0xff after each
decrement, which the target does not have. And the early return has to be the
fall-through path -- written as an early return the compiler if-converts the
tail into predicated stores, where the target branches with bxeq lr. Inverting
the condition, so the longer body sits inside the if, produces the branch.

DseVoice_CountNumActiveInChannel and DseChannel_DeallocateVoices are still asm;
their prototypes are provisional and declared in this file's header. Neither was
declared anywhere else in the tree.

No comments are added to any pmd-sky file.

Authored by Claude (Opus 5) under human direction. Confirmed by a matching
build: build/pmdsky.us/pmdsky.us.nds: OK.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
cecilarmitais
2026-08-16 14:42:05 -07:00
parent 262177377d
commit 00d4d6428c
9 changed files with 62 additions and 93 deletions

View File

@@ -1,3 +0,0 @@
#pragma once
.public DseChannel_DeallocateVoices
.public DseVoice_CountNumActiveInChannel

View File

@@ -1 +0,0 @@
#pragma once

View File

@@ -1,44 +0,0 @@
.include "asm/macros.inc"
.include "main_0207199C.inc"
.text
arm_func_start DseTrackEvent_WaitUntilFadeout
DseTrackEvent_WaitUntilFadeout: ; 0x0207199C
stmdb sp!, {r3, r4, r5, lr}
mov r5, r0
mov r0, r3
mov r4, r2
bl DseVoice_CountNumActiveInChannel
cmp r0, #0
ldrgtb r0, [r5], #-1
addle r5, r5, #1
strgt r0, [r4, #0xc]
mov r0, r5
ldmia sp!, {r3, r4, r5, pc}
arm_func_end DseTrackEvent_WaitUntilFadeout
arm_func_start DseTrackEvent_EndTrack
DseTrackEvent_EndTrack: ; 0x020719C8
stmdb sp!, {r4, lr}
ldr ip, [r2, #0x20]
mov r4, r0
cmp ip, #0
bne _020719F4
mov r1, #0
mov r0, r3
strb r1, [r2, #2]
sub r4, r4, #1
bl DseChannel_DeallocateVoices
b _02071A0C
_020719F4:
ldrh r3, [r2, #0xa]
mov r0, #1
add r3, r3, #1
strh r3, [r2, #0xa]
strb r0, [r1, #3]
ldr r4, [r2, #0x20]
_02071A0C:
mov r0, r4
ldmia sp!, {r4, pc}
arm_func_end DseTrackEvent_EndTrack

View File

@@ -1,43 +0,0 @@
.include "asm/macros.inc"
.include "main_02071A1C.inc"
.text
arm_func_start DseTrackEvent_SubLoopBegin
DseTrackEvent_SubLoopBegin: ; 0x02071A1C
stmdb sp!, {r4, lr}
ldrb r4, [r2, #6]
mov r1, #0xc
ldrb lr, [r0], #1
smulbb r1, r4, r1
add r3, r2, #0x24
str r0, [r3, r1]
add ip, r3, r1
mov r1, #0
str r1, [ip, #4]
strb lr, [ip, #8]
ldrb r3, [r2, #4]
add r1, r4, #1
strb r3, [ip, #9]
strb r1, [r2, #6]
ldmia sp!, {r4, pc}
arm_func_end DseTrackEvent_SubLoopBegin
arm_func_start DseTrackEvent_SubLoopEnd
DseTrackEvent_SubLoopEnd: ; 0x02071A5C
ldrb ip, [r2, #6]
add r3, r2, #0x24
mov r1, #0xc
sub ip, ip, #1
mla r3, ip, r1, r3
ldrb r1, [r3, #8]
subs r1, r1, #1
streqb ip, [r2, #6]
bxeq lr
str r0, [r3, #4]
strb r1, [r3, #8]
ldrb r0, [r3, #9]
strb r0, [r2, #4]
ldr r0, [r3]
bx lr
arm_func_end DseTrackEvent_SubLoopEnd

View File

@@ -3,11 +3,16 @@
#include "dse.h"
s32 DseVoice_CountNumActiveInChannel(struct dse_channel* channel);
void DseChannel_DeallocateVoices(struct dse_channel* channel);
u8* DseTrackEvent_Invalid(u8* position, struct dse_sequence* seq, struct dse_track* track, struct dse_channel* channel);
u8* DseTrackEvent_WaitSame(u8* position, struct dse_sequence* seq, struct dse_track* track, struct dse_channel* channel);
u8* DseTrackEvent_WaitDelta(u8* position, struct dse_sequence* seq, struct dse_track* track, struct dse_channel* channel);
u8* DseTrackEvent_Wait8(u8* position, struct dse_sequence* seq, struct dse_track* track, struct dse_channel* channel);
u8* DseTrackEvent_Wait16(u8* position, struct dse_sequence* seq, struct dse_track* track, struct dse_channel* channel);
u8* DseTrackEvent_Wait24(u8* position, struct dse_sequence* seq, struct dse_track* track, struct dse_channel* channel);
u8* DseTrackEvent_WaitUntilFadeout(u8* position, struct dse_sequence* seq, struct dse_track* track, struct dse_channel* channel);
u8* DseTrackEvent_EndTrack(u8* position, struct dse_sequence* seq, struct dse_track* track, struct dse_channel* channel);
#endif

View File

@@ -4,5 +4,7 @@
#include "dse.h"
u8* DseTrackEvent_MainLoopBegin(u8* position, struct dse_sequence* seq, struct dse_track* track, struct dse_channel* channel);
u8* DseTrackEvent_SubLoopBegin(u8* position, struct dse_sequence* seq, struct dse_track* track, struct dse_channel* channel);
u8* DseTrackEvent_SubLoopEnd(u8* position, struct dse_sequence* seq, struct dse_track* track, struct dse_channel* channel);
#endif

View File

@@ -253,9 +253,7 @@ Static main
Object src/main_0206C98C.o
Object asm/main_0206C9BC.o
Object src/main_0207191C.o
Object asm/main_0207199C.o
Object src/main_02071A14.o
Object asm/main_02071A1C.o
Object lib/DSE/src/main_02071A98.o
Object lib/DSE/asm/main_02071AC0.o
Object lib/DSE/src/main_02071BF4.o

View File

@@ -41,3 +41,28 @@ u8* DseTrackEvent_Wait24(u8* position, struct dse_sequence* seq, struct dse_trac
track->wait_ticks_left = track->previous_wait_ticks;
return position;
}
u8* DseTrackEvent_WaitUntilFadeout(u8* position, struct dse_sequence* seq, struct dse_track* track, struct dse_channel* channel)
{
if (DseVoice_CountNumActiveInChannel(channel) > 0) {
track->wait_ticks_left = *position;
position--;
} else {
position++;
}
return position;
}
u8* DseTrackEvent_EndTrack(u8* position, struct dse_sequence* seq, struct dse_track* track, struct dse_channel* channel)
{
if (track->loop_start == NULL) {
track->is_playing = FALSE;
position--;
DseChannel_DeallocateVoices(channel);
} else {
track->main_loop_count++;
seq->field_0x0.has_looped = TRUE;
position = track->loop_start;
}
return position;
}

View File

@@ -5,3 +5,33 @@ u8* DseTrackEvent_MainLoopBegin(u8* position, struct dse_sequence* seq, struct d
track->loop_start = position;
return position;
}
u8* DseTrackEvent_SubLoopBegin(u8* position, struct dse_sequence* seq, struct dse_track* track, struct dse_channel* channel)
{
u8 idx = track->loop_stack_index;
u8 count = *position++;
struct dse_sub_loop* loop = &track->loop_stack[idx];
loop->start = position;
loop->end = NULL;
loop->count = count;
loop->octave = track->current_octave;
track->loop_stack_index = idx + 1;
return position;
}
u8* DseTrackEvent_SubLoopEnd(u8* position, struct dse_sequence* seq, struct dse_track* track, struct dse_channel* channel)
{
int idx = track->loop_stack_index - 1;
struct dse_sub_loop* loop = &track->loop_stack[idx];
int count = loop->count - 1;
if (count != 0) {
loop->end = position;
loop->count = count;
track->current_octave = loop->octave;
return loop->start;
}
track->loop_stack_index = idx;
return position;
}