From d934bd11add0c21e3675ce4ad09f870fe3e8f66f Mon Sep 17 00:00:00 2001 From: Prakxo Date: Wed, 5 Jun 2024 16:00:06 +0200 Subject: [PATCH] link rhythm --- common.py | 1 + config/dol_slices.yml | 6 + config/symbols.yml | 1 + configure.py | 1 + include/jaudio_NES/audiostruct.h | 32 +++ include/jaudio_NES/audiowork.h | 3 + include/jaudio_NES/game64.h | 2 + include/jaudio_NES/rhythm.h | 14 +- include/jaudio_NES/sub_sys.h | 16 ++ src/static/jaudio_NES/rhythm.c | 439 +++++++++++++++++++++++++++++++ 10 files changed, 509 insertions(+), 6 deletions(-) create mode 100644 src/static/jaudio_NES/rhythm.c diff --git a/common.py b/common.py index 9d79de6e..91a52029 100644 --- a/common.py +++ b/common.py @@ -453,6 +453,7 @@ JAUDIO_FUNC_ALIGN_32 = [ "-inline off" ] JAUDIO_USER = [ + "-d _LANGUAGE_C_PLUS_PLUS", "-O0", "-char unsigned", "-fp hard", diff --git a/config/dol_slices.yml b/config/dol_slices.yml index 059e27a6..7b21146c 100644 --- a/config/dol_slices.yml +++ b/config/dol_slices.yml @@ -37,6 +37,12 @@ jaudio_NES/verysimple.c: .sdata: [0x80217b80, 0x80217b88] # jaudio_NES/game64.c: # TODO: finish # .rodata: [0x800a9938, 0x800a9b98] +jaudio_NES/rhythm.c: + .text: [0x80015a4c, 0x800165ec] + .bss: [0x8017bdd8, 0x8017be80] + .sdata: [0x80217bd0, 0x80217bd8] + .sbss: [0x802183a0, 0x802183b0] + .sdata2: [0x80218d60, 0x80218d78] jaudio_NES/aictrl.c: .text: [0x80017e80, 0x80018640] .rodata: [0x800aa500, 0x800aa518] diff --git a/config/symbols.yml b/config/symbols.yml index fba0b019..6f1abbfa 100644 --- a/config/symbols.yml +++ b/config/symbols.yml @@ -3503,6 +3503,7 @@ global: 0x80217bac: write_pointer 0x80217bb0: buffer_remain 0x80217bb4: _STOP + 0x80217bc0: sou_now_bgm_handle 0x80217bc4: SOU_ONGEN_AREA1 0x80217bc8: SOU_ONGEN_AREA2 0x80217bcc: sou_md_bgm_boost_pasent diff --git a/configure.py b/configure.py index ea52a201..f3617b25 100644 --- a/configure.py +++ b/configure.py @@ -633,6 +633,7 @@ JAUDIO_FUNC_ALIGN_32_TUS = [ ] JAUDIO_USER_TUS = [ + "rhythm.c", "verysimple.c" ] diff --git a/include/jaudio_NES/audiostruct.h b/include/jaudio_NES/audiostruct.h index 1305da72..546a8fae 100644 --- a/include/jaudio_NES/audiostruct.h +++ b/include/jaudio_NES/audiostruct.h @@ -169,6 +169,38 @@ typedef struct envp_ { /* 0x1C */ envdat* pEnvData; } envp; +/* sizeof(group) == 0x160 */ +typedef struct group_ { + struct flags_ { + /* 0x000 */ u32 flag0 : 1; + } flags; + + /* 0x004 */ u8 state; + /* 0x005 */ u8 unk4; + /* 0x006 */ u8 unk5; + /* 0x007 */ u16 tempo; + /* 0x00C */ u8 unkC[0xD4]; + /* 0x0E0 */ int unkE0; + /* 0x0E4 */ u8 E4[0x77]; + /* 0x15B */ s8 unk15B; + /* 0x15C */ s8 unk15C; +} group; + +/* sizeof(AudioGlobals) == 0x92b0 */ +typedef struct AudioGlobals { + /* 0x0000 */ u8 unk0[0x3788]; + /* 0x3788 */ group groups[5]; + /* 0x3E68 */ u8 unk3E68[0x5448]; +} AudioGlobals; + +/* sizeof(sub) >= 0xCD */ +typedef struct sub_ { + /* 0x00 */ s8 unk0[0xCB]; + /* 0xCB */ s8 unkCB; + /* 0xCD */ s8 unkCC; +} sub; + + typedef union SOUNDID_ { struct { u8 wave_id; diff --git a/include/jaudio_NES/audiowork.h b/include/jaudio_NES/audiowork.h index f3f81892..37e0a550 100644 --- a/include/jaudio_NES/audiowork.h +++ b/include/jaudio_NES/audiowork.h @@ -2,11 +2,14 @@ #define AUDIOWORK_H #include "types.h" +#include "jaudio_NES/audiostruct.h" #ifdef __cplusplus extern "C" { #endif +extern AudioGlobals AG; + #ifdef __cplusplus } #endif diff --git a/include/jaudio_NES/game64.h b/include/jaudio_NES/game64.h index ed32bfef..e8e7a8be 100644 --- a/include/jaudio_NES/game64.h +++ b/include/jaudio_NES/game64.h @@ -61,6 +61,8 @@ extern void Na_RestartPrepare(); extern u8 Na_CheckRestartReady(); extern void Na_Restart(); +extern u8 sou_now_bgm_handle; + #ifdef __cplusplus } #endif diff --git a/include/jaudio_NES/rhythm.h b/include/jaudio_NES/rhythm.h index 44becac8..d0070c63 100644 --- a/include/jaudio_NES/rhythm.h +++ b/include/jaudio_NES/rhythm.h @@ -8,13 +8,15 @@ extern "C" { #endif -extern void Na_RhythmStart(u32, s8, s8); -extern void Na_RhythmStop(u32); +extern void Na_RhythmInit(); +extern s8 Na_GetRhythmSubTrack(u32 idx); +extern void Na_RhythmStart(u32 idx, s8 arg1, s8 arg2); +extern void Na_RhythmStop(u32 idx); extern void Na_RhythmAllStop(); -extern f32 Na_GetRhythmAnimCounter(u32); -extern s8 Na_GetRhythmDelay(u32); -extern void Na_GetRhythmInfo(TempoBeat_c* rhythm); -extern void Na_SetRhythmInfo(TempoBeat_c* rhythm); +extern f32 Na_GetRhythmAnimCounter(u32 idx); +extern s8 Na_GetRhythmDelay(u32 idx); +extern void Na_GetRhythmInfo(TempoBeat_c* tempo); +extern void Na_SetRhythmInfo(TempoBeat_c* tempo); #ifdef __cplusplus } diff --git a/include/jaudio_NES/sub_sys.h b/include/jaudio_NES/sub_sys.h index 11b90af1..40405251 100644 --- a/include/jaudio_NES/sub_sys.h +++ b/include/jaudio_NES/sub_sys.h @@ -3,7 +3,23 @@ #include "types.h" #include "jaudio_NES/audiostruct.h" +#include "PR/mbi.h" + + +#define NA_MAKE_COMMAND(a0, a1, a2, a3) \ + (u32)((((a0)&0xFF) << 24) | (((a1)&0xFF) << 16) | (((a2)&0xFF) << 8) | (((a3)&0xFF) << 0)) extern s32 CreateAudioTask(Acmd* cmds, s16* pSamples, u32 nSamples, s32 param_4); +extern void Nap_SetU16(u32 command , u16 value); +extern void Nap_SetU8(u32 command, u8 value); +extern void Nap_SetS8(u32 command, s8 value); +extern void Nap_SetF32(u32 command, f32 value); +extern void Nap_SetS32(u32 command, s32 value); + +extern s8 Nap_ReadSubPort(s32, s32, s32); +extern s8 Nap_ReadGrpPort(s32, s32); + +extern s32 Nap_GetRandom(); + #endif diff --git a/src/static/jaudio_NES/rhythm.c b/src/static/jaudio_NES/rhythm.c new file mode 100644 index 00000000..5c10f629 --- /dev/null +++ b/src/static/jaudio_NES/rhythm.c @@ -0,0 +1,439 @@ +#include "jaudio_NES/rhythm.h" +#include "jaudio_NES/sub_sys.h" +#include "jaudio_NES/game64.h" +#include "jaudio_NES/audiowork.h" + +typedef struct NA_RHYTHM_BUFFER { + /* 0x0 */ u8 state; + /* 0x1 */ s8 current_subtrack; + /* 0x2 */ u8 unk2[0x2]; + /* 0x4 */ u32 current_buffer_id; + /* 0x8 */ s8 unk8; + /* 0x9 */ s8 unk9; + /* 0xA */ u8 unkA[0x2]; +} NA_RHYTHM_BUFFER; + +typedef enum RythmBuffer_State { + NA_RHYTHM_BUFFER_STOPPED, + NA_RHYTHM_BUFFER_ALLOC, + NA_RHYTHM_BUFFER_STARTED, +} RythmBuffer_State; + + +static s16 rhythm_beat_type = -1; + +static NA_RHYTHM_BUFFER rhythm_buffer[14]; + +static s8 Na_GetRhythmSeNum(s8 num, sub* sub); +static s8 Na_RhythmGrpProcess(s8 arg0, group* group); + +extern void Na_RhythmInit() { + int i; + + for (i = 0; i < 14; i++) { + rhythm_buffer[i].state = NA_RHYTHM_BUFFER_STOPPED; + rhythm_buffer[i].current_subtrack = i; + } + + Nap_SetS32(NA_MAKE_COMMAND(228, 0, 0, 0), (s32)Na_GetRhythmSeNum); + Nap_SetS32(NA_MAKE_COMMAND(228, 0, 0, 1), (s32)Na_RhythmGrpProcess); +} + +static NA_RHYTHM_BUFFER* rhythm_buffer_alloc() { + int i; + + NA_RHYTHM_BUFFER* buf; + + for (i = 0; i < 14; i++) { + buf = &rhythm_buffer[i]; + + if (buf->state == NA_RHYTHM_BUFFER_STOPPED) { + buf->state = NA_RHYTHM_BUFFER_ALLOC; + return buf; + } + } + + return nullptr; +} + +static NA_RHYTHM_BUFFER* get_rhythm_buffer(u32 idx) { + int i; + NA_RHYTHM_BUFFER* buf; + + for (i = 0; i < 14; i++) { + buf = &rhythm_buffer[i]; + + if (buf->state != NA_RHYTHM_BUFFER_STOPPED && idx == buf->current_buffer_id) { + return buf; + } + } + + return nullptr; +} + +extern s8 Na_GetRhythmSubTrack(u32 idx) { + NA_RHYTHM_BUFFER* buf; + + buf = get_rhythm_buffer(idx); + if (buf == nullptr) { + return -1; + } + return buf->current_subtrack; +} + +static void rhythm_start(NA_RHYTHM_BUFFER* buffer) { + if (buffer != nullptr) { + Nap_SetS8(NA_MAKE_COMMAND(6, 2, buffer->current_subtrack, 0), 0); + Nap_SetS8(NA_MAKE_COMMAND(6, 2, buffer->current_subtrack, 3), buffer->unk8); + Nap_SetS8(NA_MAKE_COMMAND(6, 2, buffer->current_subtrack, 7), buffer->unk9); + buffer->state = NA_RHYTHM_BUFFER_STARTED; + } +} + +static void rhythm_stop(NA_RHYTHM_BUFFER* buffer) { + if (buffer != nullptr) { + if (buffer->state == NA_RHYTHM_BUFFER_STARTED) { + Nap_SetS8(NA_MAKE_COMMAND(6, 2, buffer->current_subtrack, 0), 1); + } + + buffer->state = NA_RHYTHM_BUFFER_STOPPED; + } +} + +extern void Na_RhythmStart(u32 idx, s8 arg1, s8 arg2) { + NA_RHYTHM_BUFFER* buf; + + buf = get_rhythm_buffer(idx); + if (buf == nullptr) { + buf = rhythm_buffer_alloc(); + } + if (buf != nullptr) { + buf->current_buffer_id = idx; + buf->unk8 = arg1; + buf->unk9 = arg2; + rhythm_start(buf); + } +} + +extern void Na_RhythmStop(u32 idx) { + NA_RHYTHM_BUFFER* buf; + + buf = get_rhythm_buffer(idx); + if (buf != nullptr) { + rhythm_stop(buf); + } +} + +extern void Na_RhythmAllStop() { + int i; + NA_RHYTHM_BUFFER* buf; + + for (i = 0; i < 14; i++) { + buf = &rhythm_buffer[i]; + + if (buf->state != NA_RHYTHM_BUFFER_STOPPED) { + rhythm_stop(buf); + } + } +} + +static s16 Na_GetRhythmBeatType(void) { + if (AG.groups[sou_now_bgm_handle].flags.flag0 != 0) { + rhythm_beat_type = Nap_ReadGrpPort(sou_now_bgm_handle, 1); + } + return rhythm_beat_type; +} + +extern f32 Na_GetRhythmAnimCounter(u32 idx) { + f32 f31 = 0.0f; + NA_RHYTHM_BUFFER* buf = get_rhythm_buffer(idx); + s16 r30; + s16 r29; + int r28; + s16 r27; + + if (buf == nullptr) { + return -2.0f; + } + + if (Nap_ReadSubPort(2, buf->current_subtrack, 1) == 0) { + if (Nap_ReadSubPort(2, buf->current_subtrack, 6) <= 1) { + return -1.0f; + } + return -2.0f; + } + + r30 = Nap_ReadSubPort(2, buf->current_subtrack, 4); + r29 = Nap_ReadSubPort(2, buf->current_subtrack, 5); + r27 = Nap_ReadGrpPort(2, 3); + if (r30 == 0) { + return 0.0f; + } + + if (Na_GetRhythmBeatType() == 0) { + if (Nap_ReadGrpPort(2, 2) % 2 != 0) { + r28 = 32; + } else { + r28 = 16; + } + } else { + r28 = 24; + } + + r30 = (r29 - r30) * r28; + r30 += r27; + r29 *= r28; + f31 = (f32)r30 / (f32)r29; + return f31; +} + +extern s8 Na_GetRhythmDelay(u32 idx) { + NA_RHYTHM_BUFFER* buf; + s8 delay = 0; + + buf = get_rhythm_buffer(idx); + if (buf == nullptr) { + return -1; + } + delay = Nap_ReadSubPort(2, buf->current_subtrack, 7); + + return delay; +} + +static s8 Na_GetRhythmSeNum(s8 num, sub* sub) { + u32 rand; + + if (num == 0) { + num = 16 - sub->unkCC; + if (num == 16) { + num = 0; + } + } else { + rand = Nap_GetRandom(); + switch (sub->unkCB) { + case 0x14: + case 0x15: + case 0x16: + case 0x50: + case 0x51: + case 0x52: + case 0x5A: + num = rand & 7; + break; + case 0xC: + case 0xD: + case 0xE: + case 0x17: + case 0x18: + case 0x19: + case 0x1A: + case 0x1B: + case 0x1C: + case 0x1D: + case 0x1E: + case 0x1F: + case 0x20: + case 0x21: + case 0x22: + case 0x23: + case 0x24: + case 0x25: + case 0x26: + case 0x27: + case 0x28: + case 0x29: + case 0x2A: + case 0x2B: + case 0x2C: + case 0x2D: + case 0x2E: + case 0x37: + case 0x38: + case 0x39: + case 0x3A: + case 0x3B: + case 0x3E: + case 0x3F: + case 0x40: + case 0x41: + case 0x42: + case 0x43: + case 0x4C: + case 0x4D: + case 0x4E: + case 0x4F: + case 0x58: + case 0x59: + case 0x5E: + case 0x5F: + case 0x60: + case 0x61: + case 0x62: + case 0x63: + case 0x64: + case 0x65: + case 0x66: + case 0x67: + case 0x68: + case 0x69: + case 0x6A: + case 0x6B: + case 0x6C: + case 0x6D: + case 0x6E: + case 0x6F: + case 0x70: + case 0x71: + case 0x72: + case 0x73: + case 0x74: + case 0x75: + case 0x76: + case 0x77: + case 0x78: + case 0x79: + case 0x7A: + case 0x7B: + case 0x7C: + num = (rand % 6); + break; + case 0x53: + case 0x54: + case 0x55: + case 0x56: + case 0x57: + num = (rand % 5); + break; + case 0x3C: + case 0x3D: + case 0x5D: + num = rand & 3; + break; + case 0x5: + case 0xF: + case 0x2F: + case 0x44: + case 0x45: + case 0x46: + case 0x47: + case 0x48: + case 0x49: + case 0x4A: + case 0x4B: + num = (rand % 3); + break; + default: + num = 0; + break; + } + } + return num; +} + +extern void Na_GetRhythmInfo(TempoBeat_c* tempo) { + if (tempo != nullptr) { + tempo->tempo = (AG.groups[2].tempo / 48); + tempo->beat = Na_GetRhythmBeatType(); + } +} + +extern void Na_SetRhythmInfo(TempoBeat_c* tempo) { + (tempo != nullptr); + if ((tempo == nullptr) || (tempo->tempo == 0)) { + Nap_SetS32(NA_MAKE_COMMAND(71, 2, 0, 0), 120); + rhythm_beat_type = -1; + } else { + Nap_SetS32(NA_MAKE_COMMAND(71, 2, 0, 0), tempo->tempo); + rhythm_beat_type = tempo->beat; + } +} + +static void tempo_adjust(group* group) { + int tempo = (AG.groups[2].tempo / 48); + int newTempo; + if (AG.groups[sou_now_bgm_handle].flags.flag0 != 0) { + newTempo = (AG.groups[sou_now_bgm_handle].tempo / 48); + + if (tempo > newTempo) { + tempo--; + } else if (tempo < newTempo) { + tempo++; + } + } + group->tempo = tempo * 48; +} + +static s8 Na_RhythmGrpProcess(s8 arg0, group* group) { + int r29; + int r27; + int r30; + int r31; + (void)arg0; + int ret = 1; + r29 = 24; + static int pre_beat_type = -1; + static u8 init; + static int pre_frame_per_step = -1; + + { static u8 init; } + + tempo_adjust(group); + if (Na_GetRhythmBeatType() == 0) { + if (Nap_ReadGrpPort(2, 2) % 2 != 0) { + r29 = 32; + } else { + r29 = 16; + } + } else { + r29 = 24; + } + + r31 = Nap_ReadGrpPort(2, 3); + if (Nap_ReadGrpPort(2, 2) % 2 != 0) { + r27 = r31; + } else if (Na_GetRhythmBeatType() == 0) { + r27 = r31 + 32; + } else { + r27 = r31 + 24; + } + + if (pre_beat_type != rhythm_beat_type) { + if (pre_frame_per_step > 0) { + r31 = (r31 * (r29 / (f32)pre_frame_per_step)); + } + pre_beat_type = rhythm_beat_type; + } + pre_frame_per_step = r29; + + if (AG.groups[sou_now_bgm_handle].flags.flag0 != 0) { + int r25 = Nap_ReadGrpPort(sou_now_bgm_handle, 0); + r30 = r25 - r27; + } else { + r30 = 0; + } + + if (r30 > 24) { + r30 -= 48; + } + if (r30 < -24) { + r30 += 48; + } + + if (r30 > 1 || r30 < -1) { + if (AG.groups[2].unkE0 % 2 != 0) { + r31++; + } + } else { + r31++; + } + + if (r31 >= r29) { + r31 -= r29; + ret = 0; + } + + group->unk15B = r31; + group->unk15C = (s8)((s32)(r31 * 0x64) / r29); + + return ret; +}