diff --git a/config/rel_slices.yml b/config/rel_slices.yml index 391c0b0f..fe2d4c6c 100644 --- a/config/rel_slices.yml +++ b/config/rel_slices.yml @@ -86,6 +86,10 @@ m_view.c: .rodata: [0x806433D8, 0x80643408] sys_stacks.c: .bss: [0x812F5670, 0x812F9670] +m_vibctl.c: + .text: [0x8040387C, 0x804040F0] + .rodata: [0x80643550, 0x806436C8] + .bss: [0x812F3098, 0x812F31B8] THA_GA.c: .text: [0x80404AE0, 0x80404B40] TwoHeadArena.c: diff --git a/include/dolphin/pad.h b/include/dolphin/pad.h index 1c1980df..bc6f5501 100644 --- a/include/dolphin/pad.h +++ b/include/dolphin/pad.h @@ -7,6 +7,10 @@ extern "C" { #endif +#define PAD_MOTOR_STOP 0 +#define PAD_MOTOR_RUMBLE 1 +#define PAD_MOTOR_STOP_HARD 2 + #define PAD_BUTTON_LEFT 0x0001 #define PAD_BUTTON_RIGHT 0x0002 #define PAD_BUTTON_DOWN 0x0004 diff --git a/include/m_common_data.h b/include/m_common_data.h index 88c190b3..6ba449c7 100644 --- a/include/m_common_data.h +++ b/include/m_common_data.h @@ -187,10 +187,10 @@ typedef struct common_data_s { /* 0x028848 */ u32 train_start_timer; /* 0x02884C */ f32 train_speed; /* 0x028850 */ xyz_t train_position; - /* 0x02885C */ f32 train_mic_distance1; - /* 0x028860 */ f32 train_mic_distance2; - /* 0x028864 */ u16 train_angleY1; - /* 0x028866 */ u16 train_angleY2; + /* 0x02885C */ f32 unused_02885C; + /* 0x028860 */ f32 unused_028860; + /* 0x028864 */ u16 unused_028864; + /* 0x028866 */ u16 unused_028866; /* 0x028868 */ u8 _028868[0x028879 - 0x028868]; /* 0x028879 */ u8 auto_nwrite_count; /* 0x02887A */ lbRTC_year_t auto_nwrite_year; diff --git a/include/m_vibctl.h b/include/m_vibctl.h index 874bf34f..dce81525 100644 --- a/include/m_vibctl.h +++ b/include/m_vibctl.h @@ -7,9 +7,84 @@ extern "C" { #endif +#define mVibctl_FLAG_FORCE_STOP_NONE 0 +#define mVibctl_FLAG_FORCE_STOP0 (1 << 0) // 1 +#define mVibctl_FLAG_FORCE_STOP1 (1 << 1) // 2 +#define mVibctl_FLAG_FORCE_STOP2 (1 << 2) // 4 +#define mVibctl_FLAG_FORCE_STOP3 (1 << 3) // 8 +#define mVibctl_FLAG_FORCE_STOP_ALL (mVibctl_FLAG_FORCE_STOP0 | mVibctl_FLAG_FORCE_STOP1 | mVibctl_FLAG_FORCE_STOP2 | mVibctl_FLAG_FORCE_STOP3) // 15 + +enum { + mVibctl_ELEM_ENTRY_ATTACK, // fade-in program + mVibctl_ELEM_ENTRY_SUSTAIN, // sustain program + mVibctl_ELEM_ENTRY_RELEASE, // fade-out program + mVibctl_ELEM_ENTRY_END, // program has finished + + mVibctl_ELEM_ENTRY_NUM = mVibctl_ELEM_ENTRY_END +}; + +enum { + mVibctl_VIB_PROG_NON, // rumble config attack, shake tree attack + mVibctl_VIB_PROG_FFF, // fish touch bobber, fishing rod cast, rumble config sustain, Mouth of Truth furniture interaction attack & sustain, shovel hits soft object, net swing, axe cut attack & release, trip attack, pick weed sustain & release + mVibctl_VIB_PROG_F, // unused? + mVibctl_VIB_PROG_MF, // unused? + mVibctl_VIB_PROG_MP, // unused? + mVibctl_VIB_PROG_P, // rumble config release, shake tree release + mVibctl_VIB_PROG_FUNBARI, // unused? + mVibctl_VIB_PROG_ANAHORI, // digging with shovel + mVibctl_VIB_PROG_ANAUME, // filling hole with shovel + mVibctl_VIB_PROG_IMPACT, // fish bite bobber, shovel hits hard object + mVibctl_VIB_PROG_KI_GA_TAORERU, // axe cut sustain + mVibctl_VIB_PROG_KI_WO_YUSURU, // shake tree sustain + mVibctl_VIB_PROG_KORONODA, // trip sustain + mVibctl_VIB_PROG_SURPRISE, // Mouth of Truth furniture interaction release + mVibctl_VIB_PROG_DUMMY_B, // unused? + mVibctl_VIB_PROG_SAMPLE, // unused? + + mVibctl_VIB_PROG_NUM +}; + +#define mVibctl_ELEM_NUM 4 + +typedef struct vibration_element_entry_s { + int type; + int frames; + f32 step; +} mVibInfo_elem_entry_c; + +typedef struct vibration_element_s { + mVibInfo_elem_entry_c entries[mVibctl_ELEM_ENTRY_NUM]; + f32 step0; + f32 step1; + int now_entry; + int state_idx; + f32 frame_intensity; + int entry_frame; + f32 now_intensity; + int command; // for padmgr, PAD_MOTOR_* +} mVibElem_c; + +typedef struct vibration_info_s { + mVibElem_c* target_elem; + mVibElem_c elements[mVibctl_ELEM_NUM]; + int num_elements; + int force_stop; + int last_force_stop; +} mVibInfo_c; + +typedef struct vibration_work_data_S { + const u8* data; + int count; +} mVibWorkData_c; + extern void mVibctl_ct(); -extern void mVibctl_reset(); extern void mVibctl_init0(); +extern void mVibctl_init(); +extern void mVibctl_reset(); +extern void mVibctl_entry(int total_frames, int attack_type, int sustain_type, int release_type, int attack_frames, int sustain_frames, int release_frames, f32 step); +extern void mVibctl_simple_entry(int total_frames, int type, int attack_frames, int sustain_frames, int release_frames, f32 step); +extern void mVibctl_set_force_stop(int force_stop); +extern void mVibctl_clr_force_stop(int force_stop); #ifdef __cplusplus } diff --git a/include/padmgr.h b/include/padmgr.h index 436a81d4..205f1389 100644 --- a/include/padmgr.h +++ b/include/padmgr.h @@ -22,8 +22,8 @@ enum pads { }; typedef struct { - u8 last_intensity; - u8 now_intensity; + u8 last_command; // PAD_MOTOR_* + u8 now_command; // PAD_MOTOR_* u8 frames; u8 _pad; } Motor_t; @@ -64,18 +64,21 @@ typedef struct { extern padmgr padmgr_class; extern int padmgr_isConnectedController(int pad); +extern void padmgr_force_stop_ON(); +extern void padmgr_force_stop_OFF(); +extern void padmgr_RumbleSet(int pad, int intensity); -#define padmgr_setClient(callback, param) \ +#define padmgr_setClient(callback_proc, param) \ do { \ padmgr* mgr = &padmgr_class; \ - mgr->callback = callback; \ + mgr->callback = callback_proc; \ mgr->callback_param = param; \ } while (0) -#define padmgr_removeClient(callback, param) \ +#define padmgr_removeClient(callback_proc, param) \ do { \ padmgr* mgr = &padmgr_class; \ - if (mgr->callback == (callback) && mgr->callback_param == (param)) { \ + if (mgr->callback == (callback_proc) && mgr->callback_param == (param)) { \ mgr->callback = NULL; \ mgr->callback_param = NULL; \ } \ diff --git a/rel/m_vibctl.c b/rel/m_vibctl.c new file mode 100644 index 00000000..71dffb6b --- /dev/null +++ b/rel/m_vibctl.c @@ -0,0 +1,490 @@ +#include "m_vibctl.h" + +#include "libultra/libultra.h" +#include "padmgr.h" +#include "m_common_data.h" +#include "m_field_info.h" +#include "m_event.h" +#include "dolphin/pad.h" + +static const u8 mVW_Non[1] = { PAD_MOTOR_STOP }; + +static const u8 mVW_FFF[1] = { PAD_MOTOR_RUMBLE }; + +static const u8 mVW_F[2] = { + PAD_MOTOR_RUMBLE, + PAD_MOTOR_STOP +}; + +static const u8 mVW_MF[3] = { + PAD_MOTOR_RUMBLE, + PAD_MOTOR_STOP, + PAD_MOTOR_STOP +}; + +static const u8 mVW_MP[4] = { + PAD_MOTOR_RUMBLE, + PAD_MOTOR_STOP, + PAD_MOTOR_STOP, + PAD_MOTOR_STOP +}; + +static const u8 mVW_P[5] = { + PAD_MOTOR_RUMBLE, + PAD_MOTOR_STOP, + PAD_MOTOR_STOP, + PAD_MOTOR_STOP, + PAD_MOTOR_STOP +}; + +static const u8 mVW_funbari[8] = { + PAD_MOTOR_RUMBLE, + PAD_MOTOR_RUMBLE, + PAD_MOTOR_RUMBLE, + PAD_MOTOR_RUMBLE, + PAD_MOTOR_RUMBLE, + PAD_MOTOR_STOP_HARD, + PAD_MOTOR_STOP_HARD, + PAD_MOTOR_STOP_HARD +}; + +static const u8 mVW_anahori[8] = { + PAD_MOTOR_RUMBLE, + PAD_MOTOR_RUMBLE, + PAD_MOTOR_RUMBLE, + PAD_MOTOR_STOP, + PAD_MOTOR_STOP, + PAD_MOTOR_STOP, + PAD_MOTOR_STOP, + PAD_MOTOR_STOP +}; + +static const u8 mVW_anaume[60] = { + PAD_MOTOR_RUMBLE, + PAD_MOTOR_RUMBLE, + PAD_MOTOR_RUMBLE, + PAD_MOTOR_RUMBLE, + PAD_MOTOR_RUMBLE, + PAD_MOTOR_RUMBLE, + PAD_MOTOR_STOP, + PAD_MOTOR_STOP, + PAD_MOTOR_STOP, + PAD_MOTOR_STOP, + PAD_MOTOR_RUMBLE, + PAD_MOTOR_STOP_HARD, + PAD_MOTOR_STOP, + PAD_MOTOR_STOP, + PAD_MOTOR_STOP, + PAD_MOTOR_STOP, + PAD_MOTOR_RUMBLE, + PAD_MOTOR_STOP_HARD, + PAD_MOTOR_STOP, + PAD_MOTOR_STOP, + PAD_MOTOR_STOP, + PAD_MOTOR_STOP, + PAD_MOTOR_RUMBLE, + PAD_MOTOR_STOP_HARD, + PAD_MOTOR_STOP, + PAD_MOTOR_STOP, + PAD_MOTOR_STOP, + PAD_MOTOR_STOP, + PAD_MOTOR_RUMBLE, + PAD_MOTOR_STOP_HARD, + PAD_MOTOR_STOP, + PAD_MOTOR_STOP, + PAD_MOTOR_STOP, + PAD_MOTOR_STOP, + PAD_MOTOR_RUMBLE, + PAD_MOTOR_STOP_HARD, + PAD_MOTOR_STOP, + PAD_MOTOR_STOP, + PAD_MOTOR_STOP, + PAD_MOTOR_STOP, + PAD_MOTOR_RUMBLE, + PAD_MOTOR_STOP_HARD, + PAD_MOTOR_STOP, + PAD_MOTOR_STOP, + PAD_MOTOR_STOP, + PAD_MOTOR_STOP, + PAD_MOTOR_RUMBLE, + PAD_MOTOR_STOP_HARD, + PAD_MOTOR_STOP, + PAD_MOTOR_STOP, + PAD_MOTOR_STOP, + PAD_MOTOR_STOP, + PAD_MOTOR_RUMBLE, + PAD_MOTOR_STOP_HARD, + PAD_MOTOR_STOP, + PAD_MOTOR_RUMBLE, + PAD_MOTOR_RUMBLE, + PAD_MOTOR_RUMBLE, + PAD_MOTOR_RUMBLE, + PAD_MOTOR_STOP_HARD +}; + +static const u8 mVW_impact[9] = { + PAD_MOTOR_RUMBLE, + PAD_MOTOR_RUMBLE, + PAD_MOTOR_RUMBLE, + PAD_MOTOR_RUMBLE, + PAD_MOTOR_RUMBLE, + PAD_MOTOR_RUMBLE, + PAD_MOTOR_STOP_HARD, + PAD_MOTOR_STOP_HARD, + PAD_MOTOR_STOP_HARD +}; + +static const u8 mVW_ki_ga_taoreru[36] = { + PAD_MOTOR_RUMBLE, + PAD_MOTOR_RUMBLE, + PAD_MOTOR_RUMBLE, + PAD_MOTOR_RUMBLE, + PAD_MOTOR_RUMBLE, + PAD_MOTOR_RUMBLE, + PAD_MOTOR_STOP_HARD, + PAD_MOTOR_STOP_HARD, + PAD_MOTOR_STOP_HARD, + PAD_MOTOR_STOP, + PAD_MOTOR_STOP, + PAD_MOTOR_STOP, + PAD_MOTOR_STOP, + PAD_MOTOR_STOP, + PAD_MOTOR_STOP, + PAD_MOTOR_STOP, + PAD_MOTOR_STOP, + PAD_MOTOR_STOP, + PAD_MOTOR_STOP, + PAD_MOTOR_STOP, + PAD_MOTOR_RUMBLE, + PAD_MOTOR_STOP, + PAD_MOTOR_STOP, + PAD_MOTOR_STOP, + PAD_MOTOR_STOP, + PAD_MOTOR_RUMBLE, + PAD_MOTOR_STOP, + PAD_MOTOR_STOP, + PAD_MOTOR_STOP, + PAD_MOTOR_STOP, + PAD_MOTOR_RUMBLE, + PAD_MOTOR_STOP, + PAD_MOTOR_STOP, + PAD_MOTOR_STOP, + PAD_MOTOR_STOP, + PAD_MOTOR_RUMBLE +}; + +static const u8 mVW_ki_wo_yusuru[13] = { + PAD_MOTOR_RUMBLE, + PAD_MOTOR_RUMBLE, + PAD_MOTOR_RUMBLE, + PAD_MOTOR_RUMBLE, + PAD_MOTOR_RUMBLE, + PAD_MOTOR_STOP_HARD, + PAD_MOTOR_STOP_HARD, + PAD_MOTOR_STOP_HARD, + PAD_MOTOR_STOP, + PAD_MOTOR_STOP, + PAD_MOTOR_STOP, + PAD_MOTOR_STOP, + PAD_MOTOR_STOP +}; + +static const u8 mVW_koronoda[14] = { + PAD_MOTOR_RUMBLE, + PAD_MOTOR_RUMBLE, + PAD_MOTOR_RUMBLE, + PAD_MOTOR_RUMBLE, + PAD_MOTOR_RUMBLE, + PAD_MOTOR_RUMBLE, + PAD_MOTOR_STOP_HARD, + PAD_MOTOR_STOP_HARD, + PAD_MOTOR_STOP_HARD, + PAD_MOTOR_STOP, + PAD_MOTOR_STOP, + PAD_MOTOR_RUMBLE, + PAD_MOTOR_STOP, + PAD_MOTOR_STOP +}; + +static const u8 mVW_surprise[7] = { + PAD_MOTOR_RUMBLE, + PAD_MOTOR_RUMBLE, + PAD_MOTOR_RUMBLE, + PAD_MOTOR_RUMBLE, + PAD_MOTOR_STOP_HARD, + PAD_MOTOR_STOP_HARD, + PAD_MOTOR_STOP +}; + +static const u8 mVW_dummy_b[1] = { PAD_MOTOR_RUMBLE }; + +static const u8 mVW_sample[13] = { + PAD_MOTOR_RUMBLE, + PAD_MOTOR_RUMBLE, + PAD_MOTOR_RUMBLE, + PAD_MOTOR_RUMBLE, + PAD_MOTOR_RUMBLE, + PAD_MOTOR_STOP_HARD, + PAD_MOTOR_STOP_HARD, + PAD_MOTOR_STOP_HARD, + PAD_MOTOR_STOP, + PAD_MOTOR_STOP, + PAD_MOTOR_STOP, + PAD_MOTOR_STOP, + PAD_MOTOR_STOP +}; + +#define VIB_PROG(name) { mVW_##name, ARRAY_SIZE(mVW_##name, u8) } +static const mVibWorkData_c mVW_data[mVibctl_VIB_PROG_NUM] = { + VIB_PROG(Non), + VIB_PROG(FFF), + VIB_PROG(F), + VIB_PROG(MF), + VIB_PROG(MP), + VIB_PROG(P), + VIB_PROG(funbari), + VIB_PROG(anahori), + VIB_PROG(anaume), + VIB_PROG(impact), + VIB_PROG(ki_ga_taoreru), + VIB_PROG(ki_wo_yusuru), + VIB_PROG(koronoda), + VIB_PROG(surprise), + VIB_PROG(dummy_b), + VIB_PROG(sample) +}; + +static mVibInfo_c mVib_info; + +static void mVibElem_move(mVibElem_c* elem) { + mVibInfo_elem_entry_c* now_entry = elem->entries + elem->now_entry; + int type = now_entry->type; + const mVibWorkData_c* work_data = &mVW_data[type]; + + elem->entry_frame++; + elem->frame_intensity = elem->step1 * elem->step0; + + if (elem->now_entry == mVibctl_ELEM_ENTRY_ATTACK) { + elem->frame_intensity *= (f32)elem->entry_frame * now_entry->step; + } + else if (elem->now_entry == mVibctl_ELEM_ENTRY_RELEASE) { + elem->frame_intensity *= now_entry->step * (now_entry->frames - elem->entry_frame); + } + + if (work_data->data[elem->state_idx] == PAD_MOTOR_RUMBLE) { + /* only rumble when our current intensity has reached or surpassed 1.0f */ + elem->now_intensity += elem->frame_intensity; + + if (elem->now_intensity >= 1.0f) { + elem->command = PAD_MOTOR_RUMBLE; + elem->now_intensity -= 1.0f; + } + else { + elem->command = PAD_MOTOR_STOP; + } + } + else { + elem->command = work_data->data[elem->state_idx]; + } + + { + /* increment current program state index */ + int state_count = work_data->count; + int now_state = elem->state_idx + 1; + elem->state_idx = now_state; + + /* check if program state index has rolled over */ + if (now_state >= state_count) { + elem->state_idx = 0; + } + + /* check if current stage frames have ended, and if so, advanced to next one */ + if (elem->entry_frame >= now_entry->frames) { + elem->now_entry++; + elem->entry_frame = 0; + elem->state_idx = 0; + } + } +} + +static void mVibInfo_elem_entry(mVibInfo_c* vib_info, int total_frames, int attack_type, int sustain_type, int release_type, int attack_frames, int sustain_frames, int release_frames, f32 step) { + if ((attack_frames != 0 || sustain_frames != 0 || release_frames != 0) && (step < 640.0f && vib_info->num_elements < mVibctl_ELEM_NUM)) { + mVibElem_c* elem = vib_info->elements + vib_info->num_elements; + bzero(elem, sizeof(mVibElem_c)); + + /* set attack phase configuration */ + elem->entries[mVibctl_ELEM_ENTRY_ATTACK].type = attack_type; + elem->entries[mVibctl_ELEM_ENTRY_ATTACK].frames = attack_frames; + elem->entries[mVibctl_ELEM_ENTRY_ATTACK].step = (attack_frames > 0) ? (1.0f / (f32)attack_frames) : -1.0f; + + /* set sustain phase configuration */ + elem->entries[mVibctl_ELEM_ENTRY_SUSTAIN].type = sustain_type; + elem->entries[mVibctl_ELEM_ENTRY_SUSTAIN].frames = sustain_frames; + elem->entries[mVibctl_ELEM_ENTRY_SUSTAIN].step = (sustain_frames > 0) ? (1.0f / (f32)sustain_frames) : -1.0f; + + /* set release phase configuration */ + elem->entries[mVibctl_ELEM_ENTRY_RELEASE].type = release_type; + elem->entries[mVibctl_ELEM_ENTRY_RELEASE].frames = release_frames; + elem->entries[mVibctl_ELEM_ENTRY_RELEASE].step = (release_frames > 0) ? (1.0f / (f32)release_frames) : -1.0f; + + if (attack_frames == 0) { + if (sustain_frames == 0) { + elem->now_entry = mVibctl_ELEM_ENTRY_RELEASE; + } + else { + elem->now_entry = mVibctl_ELEM_ENTRY_SUSTAIN; + } + } + + elem->step1 = total_frames * 0.01f; + + if (step < 41.0f) { + elem->step0 = 1.0f; + } + else { + elem->step0 = 1.0f / (step - 40.0f); + } + + vib_info->num_elements++; + } +} + +static void mVibInfo_elem_delete(mVibInfo_c* vib_info, int elem_no) { + int i; + int n_elems = vib_info->num_elements - 1; + + for (i = elem_no; i < n_elems; i++) { + mVibElem_c* dst_elem = vib_info->elements + (i + 1); + mVibElem_c* src_elem = vib_info->elements + i; + bcopy(dst_elem, src_elem, sizeof(mVibElem_c)); + } + + bzero(vib_info->elements + n_elems, sizeof(mVibElem_c)); + vib_info->num_elements--; +} + +static void mVibInfo_set_force_stop(mVibInfo_c* vib_info, int force_stop) { + vib_info->force_stop |= force_stop; +} + +static void mVibInfo_clr_force_stop(mVibInfo_c* vib_info, int force_stop) { + vib_info->force_stop &= ~force_stop; +} + +static void mVibInfo_set_target_elem(mVibInfo_c* vib_info) { + int n_elems = vib_info->num_elements; + f32 max = -10000.0f; + mVibElem_c* elem = vib_info->elements; + mVibElem_c* selected = NULL; + int i; + + for (i = 0; i < n_elems; i++) { + if (elem->frame_intensity > max) { + max = elem->frame_intensity; + selected = elem; + } + elem++; + } + + vib_info->target_elem = selected; +} + +static void mVibInfo_force(mVibInfo_c* vib_info) { + if (Save_Get(config.vibration_enabled)) { + mVibInfo_set_force_stop(vib_info, mVibctl_FLAG_FORCE_STOP0); + } + else { + mVibInfo_clr_force_stop(vib_info, mVibctl_FLAG_FORCE_STOP0); + } + + if (vib_info->force_stop != mVibctl_FLAG_FORCE_STOP_NONE && vib_info->last_force_stop == mVibctl_FLAG_FORCE_STOP_NONE) { + padmgr_force_stop_ON(); + } + else if (vib_info->force_stop == mVibctl_FLAG_FORCE_STOP_NONE && vib_info->last_force_stop != mVibctl_FLAG_FORCE_STOP_NONE) { + padmgr_force_stop_OFF(); + } + + vib_info->last_force_stop = vib_info->force_stop; +} + +static void mVibInfo_set_motor(mVibInfo_c* vib_info) { + if (vib_info->target_elem != NULL) { + padmgr_RumbleSet(PAD0, vib_info->target_elem->command); + } + else { + padmgr_RumbleSet(PAD0, PAD_MOTOR_STOP); + } +} + +static void mVibInfo_move(mVibInfo_c* vib_info) { + int i; + + mVibInfo_force(vib_info); + + for (i = 0; i < vib_info->num_elements; i++) { + mVibElem_move(vib_info->elements + i); + } + + for (i = vib_info->num_elements - 1; i >= 0; i--) { + if (vib_info->elements[i].now_entry >= mVibctl_ELEM_ENTRY_END) { + mVibInfo_elem_delete(vib_info, i); + } + } + + mVibInfo_set_target_elem(vib_info); + + if (vib_info->force_stop == mVibctl_FLAG_FORCE_STOP_NONE) { + mVibInfo_set_motor(vib_info); + } +} + +static void mVibctl_check_title_demo() { + if (mFI_CheckFieldData() && mFI_GET_TYPE(mFI_GetFieldId()) == mFI_FIELDTYPE_FG && mEv_CheckTitleDemo() > 0) { + mVibctl_set_force_stop(mVibctl_FLAG_FORCE_STOP2); + } + else { + mVibctl_clr_force_stop(mVibctl_FLAG_FORCE_STOP2); + } +} + +static void mVibctl_callback(void* arg) { + mVibctl_check_title_demo(); + mVibInfo_move(&mVib_info); +} + +extern void mVibctl_ct() { + bzero(&mVib_info, sizeof(mVibInfo_c)); +} + +extern void mVibctl_init0() { + mVibctl_ct(); +} + +extern void mVibctl_init() { + padmgr_setClient(&mVibctl_callback, NULL); +} + +extern void mVibctl_cleanup() { + padmgr_removeClient(&mVibctl_callback, NULL); +} + +extern void mVibctl_reset() { + mVibctl_clr_force_stop(mVibctl_FLAG_FORCE_STOP_ALL); + mVibctl_set_force_stop(mVibctl_FLAG_FORCE_STOP3); +} + +extern void mVibctl_entry(int total_frames, int attack_type, int sustain_type, int release_type, int attack_frames, int sustain_frames, int release_frames, f32 step) { + mVibInfo_elem_entry(&mVib_info, total_frames, attack_type, sustain_type, release_type, attack_frames, sustain_frames, release_frames, step); +} + +extern void mVibctl_simple_entry(int total_frames, int type, int attack_frames, int sustain_frames, int release_frames, f32 step) { + mVibInfo_elem_entry(&mVib_info, total_frames, type, type, type, attack_frames, sustain_frames, release_frames, step); +} + +extern void mVibctl_set_force_stop(int force_stop) { + mVibInfo_set_force_stop(&mVib_info, force_stop); +} + +extern void mVibctl_clr_force_stop(int force_stop) { + mVibInfo_clr_force_stop(&mVib_info, force_stop); +}