fix archive creation, must be o2r

This commit is contained in:
Demur Rumed 2025-04-20 21:25:39 +00:00
commit 17d2e39a57
9 changed files with 1598 additions and 1765 deletions

View file

@ -13,61 +13,56 @@
#include "overlays/actors/ovl_Boss_Goma/z_boss_goma.h"
std::vector<uint32_t> buttonList = { BTN_A, BTN_B, BTN_CUP, BTN_CDOWN, BTN_CLEFT, BTN_CRIGHT, BTN_L,
BTN_Z, BTN_R, BTN_START, BTN_DUP, BTN_DDOWN, BTN_DLEFT, BTN_DRIGHT };
//Declarations specific to chests.
BTN_Z, BTN_R, BTN_START, BTN_DUP, BTN_DDOWN, BTN_DLEFT, BTN_DRIGHT };
// Declarations specific to chests.
#include "overlays/actors/ovl_En_Box/z_en_box.h"
extern "C" {
void EnBox_WaitOpen(EnBox*, PlayState*);
}
//Declarations specific to Babas.
// Declarations specific to Babas.
#include "overlays/actors/ovl_En_Karebaba/z_en_karebaba.h"
extern "C" {
void EnKarebaba_DeadItemDrop(EnKarebaba*, PlayState*);
}
//Declarations specific to Torches
// Declarations specific to Torches
#include "overlays/actors/ovl_Obj_Syokudai/z_obj_syokudai.h"
//Declarations specific to dogs
// Declarations specific to dogs
#include "overlays/actors/ovl_En_Dog/z_en_dog.h"
extern "C" {
void EnDog_FollowPlayer(EnDog*, PlayState*);
s8 EnDog_CanFollow(EnDog*, PlayState*);
}
//User data for the general helper VA.
typedef struct
{
// User data for the general helper VA.
typedef struct {
s16 currentScene;
s8 currentRoom;
bool currentRoomClear;
}GeneralHelperData;
typedef struct
{
} GeneralHelperData;
typedef struct {
f32 linearVelocity;
int framesUntilChime;
}AudioCompassData;
typedef struct
{
} AudioCompassData;
typedef struct {
int framesUntilAboveChime;
}SwitchData;
} SwitchData;
// Begin actor-specific policy callbacks.
// Begin actor-specific policy callbacks.
void accessible_en_ishi(AccessibleActor* actor) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EN_OCTAROCK_ROCK, false);
//ActorAccessibility_PlaySpecialSound(actor, NA_SE_EN_OCTAROCK_ROCK);
// ActorAccessibility_PlaySpecialSound(actor, NA_SE_EN_OCTAROCK_ROCK);
}
void accessible_en_NPC_Gen(AccessibleActor* actor) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_VO_NB_LAUGH, false);
}
void accessible_en_chest(AccessibleActor* actor) {
Player* player = GET_PLAYER(actor->play);
EnBox* chest = (EnBox*)actor->actor;
if (chest->actionFunc != EnBox_WaitOpen)
@ -77,37 +72,35 @@ void accessible_en_chest(AccessibleActor* actor) {
if (chest->type <= 8 && chest->type >= 5) {
size = 15; // small
} else {
size = 30;//large
size = 30; // large
}
if (!(treasureFlag >= 20 && treasureFlag < 32)) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_TBOX_UNLOCK, false);
}
//Only chests that are "waiting to be opened" should play a sound. Chests which have not yet appeared (because some enemy has not been killed, switch has not been hit, etc) will not be in this action mode.
// Only chests that are "waiting to be opened" should play a sound. Chests which have not yet appeared (because some
// enemy has not been killed, switch has not been hit, etc) will not be in this action mode.
f32 leftAngle = actor->actor->world.rot.y - 16384;
f32 velocityXRight = Math_SinS(leftAngle);
f32 velocityZRight = Math_CosS(leftAngle);
f32 frontAngle = actor->actor->world.rot.y;
f32 velocityXFront = Math_SinS(frontAngle);
f32 velocityZFront = Math_CosS(frontAngle);
f32 xdist = (player->actor.world.pos.x - actor->actor->world.pos.x) * velocityXFront +
(player->actor.world.pos.z-actor->actor->world.pos.z) * velocityZFront;
f32 zdist = fabs((player->actor.world.pos.x - actor->actor->world.pos.x) * velocityXRight +
(player->actor.world.pos.z-actor->actor->world.pos.z) * velocityZRight);
f32 xdist = (player->actor.world.pos.x - actor->actor->world.pos.x) * velocityXFront +
(player->actor.world.pos.z - actor->actor->world.pos.z) * velocityZFront;
f32 zdist = fabs((player->actor.world.pos.x - actor->actor->world.pos.x) * velocityXRight +
(player->actor.world.pos.z - actor->actor->world.pos.z) * velocityZRight);
if ((xdist - size / 2) < 0) {
ActorAccessibility_SetSoundPitch(actor, 0, 0.5);
} else if ((xdist + size / 2) > 0 && zdist < size / 2 && xdist < 150.0) {
ActorAccessibility_PlaySoundForActor(actor, 1, NA_SE_EV_DIAMOND_SWITCH, false);
}
}
void accessible_en_gerudo(AccessibleActor* actor) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_VO_NB_LAUGH, false);//update sound for ones that detect you
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_VO_NB_LAUGH, false); // update sound for ones that detect you
}
void accessible_en_Sign(AccessibleActor* actor) {
@ -154,7 +147,7 @@ void accessible_torches(AccessibleActor* actor) {
return;
}
//unlit permanent torches
// unlit permanent torches
if ((actor->actor->params) == 8192) {
if (torche->litTimer == 0) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_IT_BOMB_IGNIT, false);
@ -162,7 +155,7 @@ void accessible_torches(AccessibleActor* actor) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EN_ANUBIS_FIRE, false);
}
}
//lit permanent torches
// lit permanent torches
if ((actor->actor->params) == 9216 || (actor->actor->params) == 962) {
actor->policy.volume = 0.5;
@ -187,20 +180,17 @@ bool accessible_switch_init(AccessibleActor* actor) {
SwitchData* data = (SwitchData*)malloc(sizeof(SwitchData));
data->framesUntilAboveChime = 0;
if (data == NULL)
return false;//failure to allocate memory.
actor->userData = (void*) data;
return false; // failure to allocate memory.
actor->userData = (void*)data;
return true;
}
void accessible_switch_cleanup(AccessibleActor* actor)
{
void accessible_switch_cleanup(AccessibleActor* actor) {
free(actor->userData);
}
void accessible_switch(AccessibleActor * actor) {
void accessible_switch(AccessibleActor* actor) {
SwitchData* data = (SwitchData*)actor->userData;
SwitchData* data = (SwitchData*)actor->userData;
Player* player = GET_PLAYER(actor->play);
ObjSwitch* sw = (ObjSwitch*)actor->actor;
@ -211,26 +201,24 @@ void accessible_switch_cleanup(AccessibleActor* actor)
}
if (scale.y >= 33.0f / 200.0f) {
if (actor->play->sceneNum == 0 && actor->play->roomCtx.curRoom.num == 5 && actor->xzDistToPlayer < 20) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_DIAMOND_SWITCH, false);//Should result in same behaviour.
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_DIAMOND_SWITCH,
false); // Should result in same behaviour.
}
if (actor->frameCount % 30 != 0) {
return;
}
ActorAccessibility_PlaySoundForActor(actor, 1, NA_SE_EV_FOOT_SWITCH, false);
}
}
else if (actor->frameCount % 30 != 0) {
}
} else if (actor->frameCount % 30 != 0) {
return;
}
else if ((actor->actor->params & 7) == 1) {
} else if ((actor->actor->params & 7) == 1) {
if (actor->xyzDistToPlayer > 800) {
return;
}
if (scale.y >= 33.0f / 200.0f) { //(!(Flags_GetSwitch(actor->play, (actor->params >> 8 & 0x3F)))) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_IT_HAMMER_HIT, false);
}
}
else if ((actor->actor->params & 7) == 2) {
} else if ((actor->actor->params & 7) == 2) {
if (sw->eyeTexIndex == 0) { //(!(Flags_GetSwitch(actor->play, (actor->params >> 8 & 0x3F))))
// make it only play for open eye
actor->policy.aimAssist.isProvider = true;
@ -243,9 +231,7 @@ void accessible_switch_cleanup(AccessibleActor* actor)
return;
}
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_DIAMOND_SWITCH, false);
}
}
void accessible_larva(AccessibleActor* actor) {
@ -261,7 +247,6 @@ void accessible_va_prototype(AccessibleActor* actor) {
Player* player = GET_PLAYER(actor->play);
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_IT_BOMB_EXPLOSION, false);
}
void accessible_maruta(AccessibleActor* actor) {
@ -279,7 +264,7 @@ void accessible_area_change(AccessibleActor* actor) {
actor->play->sceneNum != 82) {
return;
}
/*switch (actor->sceneIndex) {
/*switch (actor->sceneIndex) {
case 85 || 91:
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_SARIA_MELODY, false);
case 81:
@ -287,9 +272,9 @@ void accessible_area_change(AccessibleActor* actor) {
case 0:
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_FANTOM_WARP_L, false);
}*/
//hyrule field attenuation
if (actor->play->sceneNum == 81) {
// hyrule field attenuation
if (actor->play->sceneNum == 81) {
if (actor->xzDistToPlayer > 700) {
actor->policy.distance = actor->xzDistToPlayer * 1.2;
if (actor->xzDistToPlayer > 8000) {
@ -302,145 +287,142 @@ void accessible_area_change(AccessibleActor* actor) {
}
}
}
//kakariko village attenuation
else if (actor->play->sceneNum == 82) {
if (actor->sceneIndex == 83 || actor->sceneIndex == 81 || actor->sceneIndex == 96) {
actor->policy.runsAlways = true;
actor->policy.ydist = 5000;
if (actor->xzDistToPlayer > 700) {
if (actor->sceneIndex == 81) {
actor->policy.distance = actor->xyzDistToPlayer * 1.4;
} else {
actor->policy.distance = actor->xyzDistToPlayer * 1.2;
}
if (actor->xzDistToPlayer > 8000) {
return;
}
// kakariko village attenuation
else if (actor->play->sceneNum == 82) {
if (actor->sceneIndex == 83 || actor->sceneIndex == 81 || actor->sceneIndex == 96) {
actor->policy.runsAlways = true;
actor->policy.ydist = 5000;
if (actor->xzDistToPlayer > 700) {
if (actor->sceneIndex == 81) {
actor->policy.distance = actor->xyzDistToPlayer * 1.4;
} else {
actor->policy.distance = 1500;
if (actor->xzDistToPlayer > 1500) {
return;
}
actor->policy.distance = actor->xyzDistToPlayer * 1.2;
}
} else if (actor->sceneIndex == 8) {
if (!(((gSaveContext.eventChkInf[6]) >> (7)) & 1))
return;
}
else {
actor->policy.ydist = 500;
actor->policy.distance = 1000;
if (actor->xzDistToPlayer > 1000) {
if (actor->xzDistToPlayer > 8000) {
return;
}
} else {
actor->policy.distance = 1500;
if (actor->xzDistToPlayer > 1500) {
return;
}
}
}
else if (actor->play->sceneNum == 91 || actor->play->sceneNum == 69 || actor->play->sceneNum == 70) {
} else if (actor->sceneIndex == 8) {
if (!(((gSaveContext.eventChkInf[6]) >> (7)) & 1))
return;
} else {
actor->policy.ydist = 500;
actor->policy.distance = 1000;
if (actor->xzDistToPlayer > 1000) {
return;
}
}
/* if (actor->play->sceneNum <= 11) {
actor->policy.distance = 500;
}*/
else {
if (actor->xzDistToPlayer > 1500) {
return;
}
}
else if (actor->play->sceneNum == 91 || actor->play->sceneNum == 69 || actor->play->sceneNum == 70) {
actor->policy.distance = 1000;
if (actor->xzDistToPlayer > 1000) {
return;
}
}
/* if (actor->play->sceneNum <= 11) {
actor->policy.distance = 500;
}*/
else {
if (actor->xzDistToPlayer > 1500) {
return;
}
}
if (actor->sceneIndex == 85 || actor->sceneIndex == 91) {
if (actor->play->sceneNum == 91 && gSaveContext.entranceIndex != 1504 && gSaveContext.entranceIndex != 1246) {
return;
}
if (actor->play->sceneNum == 85 && actor->world.pos.y < 0) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_HORSE_RUN_LEVEL, false);
} else {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_SARIA_MELODY, false);
}
//kokiri forest and lost woods
// kokiri forest and lost woods
} else if (actor->play->sceneNum >= 17 && actor->play->sceneNum <= 25) {
return; // dont check for entrances while in boss rooms
} else if (actor->sceneIndex == 81) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_HORSE_RUN_LEVEL, false);
//hyrule field
} else if (actor->sceneIndex == 10 && actor->play->sceneNum != 85) {//temp
// hyrule field
} else if (actor->sceneIndex == 10 && actor->play->sceneNum != 85) { // temp
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_OC_DOOR_OPEN, false);
} else if (actor->sceneIndex <= 11) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_FANTOM_WARP_L, false);
//dungeons
// dungeons
} else if (actor->sceneIndex >= 27 && actor->sceneIndex <= 29) {
if (actor->play->sceneNum >= 32 && actor->play->sceneNum <= 34) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_HORSE_RUN_LEVEL, false);
} else {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_SMALL_DOG_BARK, false);
}
}
} else if (actor->sceneIndex >= 30 && actor->sceneIndex <= 33) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_SMALL_DOG_BARK, false);
//market sound
// market sound
} else if ((actor->sceneIndex >= 34 && actor->sceneIndex <= 36) || actor->sceneIndex == 67) {
if (actor->play->sceneNum == 67) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_SMALL_DOG_BARK, false);
} else {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_STONE_BOUND, false);
}
//ToT sound
// ToT sound
} else if (actor->sceneIndex == 69 || actor->sceneIndex == 70) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EN_MUSI_SINK, false);
} else if (actor->sceneIndex == 82) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_CHICKEN_CRY_M, false);
//kakariko sound
// kakariko sound
} else if (actor->sceneIndex == 83) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EN_PO_APPEAR, false);
//graveyard sound
} else if (actor->sceneIndex == 84 || actor->sceneIndex == 88 || actor->sceneIndex == 89) { //last one is zora fountain maybe seperate?
// graveyard sound
} else if (actor->sceneIndex == 84 || actor->sceneIndex == 88 ||
actor->sceneIndex == 89) { // last one is zora fountain maybe seperate?
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_RIVER_STREAM_S, false);
//zora sound
} else if (actor->sceneIndex == 86) {//might not need to exist
//forest medow sound
// zora sound
} else if (actor->sceneIndex == 86) { // might not need to exist
// forest medow sound
} else if (actor->sceneIndex == 87) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_WATER_WALL, false);
//Lake Hylia sound
} else if (actor->sceneIndex == 90 || actor->sceneIndex == 93) { //gerudo valley and fortress
// Lake Hylia sound
} else if (actor->sceneIndex == 90 || actor->sceneIndex == 93) { // gerudo valley and fortress
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EN_GERUDOFT_BREATH, false);
//gerudo valley sound
} else if (actor->sceneIndex == 92 || actor->sceneIndex == 94) {//haunted wasteland and desert colosus
// gerudo valley sound
} else if (actor->sceneIndex == 92 || actor->sceneIndex == 94) { // haunted wasteland and desert colosus
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_SAND_STORM, false);
} else if (actor->sceneIndex == 100 || actor->sceneIndex ==95) {
} else if (actor->sceneIndex == 100 || actor->sceneIndex == 95) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_BRIDGE_OPEN, false);
//Hyrule Castle sound
// Hyrule Castle sound
} else if (actor->sceneIndex == 96) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EN_DODO_K_ROLL, false);
//DMT sound
// DMT sound
} else if (actor->sceneIndex == 97) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EN_DODO_K_LAVA, false);
//DMC sound
// DMC sound
} else if (actor->sceneIndex == 98) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EN_DARUNIA_HIT_BREAST, false);
//Goron City
// Goron City
} else if (actor->sceneIndex == 99) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_COW_CRY, false);
//Lon Lon
// Lon Lon
} else if (actor->sceneIndex >= 17 && actor->sceneIndex <= 25) {
return;//boss rooms
}
else {
return; // boss rooms
} else {
actor->policy.distance = 500;
if (actor->play->sceneNum == 83) {
actor->policy.ydist = 0;
}
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_OC_DOOR_OPEN, false);
}
}
void accessible_231_dekus(AccessibleActor* actor) {
if (actor->actor->params == 1) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EN_NUTS_FAINT, false);
ActorAccessibility_SetSoundPitch(actor, 0, 1.0);
@ -455,7 +437,6 @@ void accessible_231_dekus(AccessibleActor* actor) {
} else {
return;
}
}
void accessible_hana(AccessibleActor* actor) {
@ -464,7 +445,6 @@ void accessible_hana(AccessibleActor* actor) {
} else if (actor->actor->params == 0) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_DIG_UP, false);
}
}
void accessible_climable(AccessibleActor* actor) {
@ -482,35 +462,36 @@ void accessible_en_guard(AccessibleActor* actor) {
f32 guardsfx = NA_SE_IT_SWORD_IMPACT;
if (fabs(actor->actor->world.pos.x - player->actor.world.pos.x) >
fabs(actor->actor->world.pos.z - player->actor.world.pos.z)) {
if (fabs(actor->actor->shape.rot.y - 16384) <1000) { if (actor->actor->world.pos.x < player->actor.world.pos.x) {
ActorAccessibility_PlaySoundForActor(actor, 0, guardsfx, false);
ActorAccessibility_SetSoundPitch(actor, 0, 2.0);
} else {
ActorAccessibility_PlaySoundForActor(actor, 0, guardsfx, false);
ActorAccessibility_SetSoundPitch(actor, 0, 0.2);
}
} else if ((actor->actor->shape.rot.y + 16384)<1000) {
if (actor->actor->world.pos.x < player->actor.world.pos.x) {
ActorAccessibility_PlaySoundForActor(actor, 0, guardsfx, false);
ActorAccessibility_SetSoundPitch(actor, 0, 0.2);
} else {
ActorAccessibility_PlaySoundForActor(actor, 0, guardsfx, false);
ActorAccessibility_SetSoundPitch(actor, 0, 2.0);
}
} else {
ActorAccessibility_PlaySoundForActor(actor, 0, guardsfx, false);
ActorAccessibility_SetSoundPitch(actor, 0, 1.0);
}
} else {
if (fabs(actor->actor->shape.rot.y) < 1000) {
if (actor->actor->world.pos.z < player->actor.world.pos.z) {
if (fabs(actor->actor->shape.rot.y - 16384) < 1000) {
if (actor->actor->world.pos.x < player->actor.world.pos.x) {
ActorAccessibility_PlaySoundForActor(actor, 0, guardsfx, false);
ActorAccessibility_SetSoundPitch(actor, 0, 2.0);
} else {
ActorAccessibility_PlaySoundForActor(actor, 0, guardsfx, false);
ActorAccessibility_SetSoundPitch(actor, 0, 0.2);
}
} else if (fabs(actor->actor->shape.rot.y+32768)<1000) {
} else if ((actor->actor->shape.rot.y + 16384) < 1000) {
if (actor->actor->world.pos.x < player->actor.world.pos.x) {
ActorAccessibility_PlaySoundForActor(actor, 0, guardsfx, false);
ActorAccessibility_SetSoundPitch(actor, 0, 0.2);
} else {
ActorAccessibility_PlaySoundForActor(actor, 0, guardsfx, false);
ActorAccessibility_SetSoundPitch(actor, 0, 2.0);
}
} else {
ActorAccessibility_PlaySoundForActor(actor, 0, guardsfx, false);
ActorAccessibility_SetSoundPitch(actor, 0, 1.0);
}
} else {
if (fabs(actor->actor->shape.rot.y) < 1000) {
if (actor->actor->world.pos.z < player->actor.world.pos.z) {
ActorAccessibility_PlaySoundForActor(actor, 0, guardsfx, false);
ActorAccessibility_SetSoundPitch(actor, 0, 2.0);
} else {
ActorAccessibility_PlaySoundForActor(actor, 0, guardsfx, false);
ActorAccessibility_SetSoundPitch(actor, 0, 0.2);
}
} else if (fabs(actor->actor->shape.rot.y + 32768) < 1000) {
if (actor->actor->world.pos.z < player->actor.world.pos.z) {
ActorAccessibility_PlaySoundForActor(actor, 0, guardsfx, false);
ActorAccessibility_SetSoundPitch(actor, 0, 0.2);
@ -523,8 +504,6 @@ void accessible_en_guard(AccessibleActor* actor) {
ActorAccessibility_SetSoundPitch(actor, 0, 1.0);
}
}
}
void accessible_en_dogs(AccessibleActor* actor) {
@ -533,22 +512,19 @@ void accessible_en_dogs(AccessibleActor* actor) {
dog->actionFunc = EnDog_FollowPlayer;
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_DIAMOND_SWITCH, false);
ActorAccessibility_SetSoundPitch(actor, 0, 1.0);
}
if (actor->frameCount % 30 != 0) {
return;
}
if (actor->actor->params == 608 || actor->actor->params == 336 || actor->actor->params == 304 ||
actor->actor->params == 3088 ||
actor->actor->params == 2576 || actor->actor->params <0) {
actor->actor->params == 3088 || actor->actor->params == 2576 || actor->actor->params < 0) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_SMALL_DOG_BARK, false);
ActorAccessibility_SetSoundPitch(actor, 0, 2.0);
} else {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_SMALL_DOG_BARK, false);
ActorAccessibility_SetSoundPitch(actor, 0, 0.5);
}
}
void accessible_goma(AccessibleActor* actor) {
@ -562,19 +538,18 @@ void accessible_door_of_time(AccessibleActor* actor) {
ActorAccessibility_PlaySampleForActor(actor, 0, "Chanting", false);
ActorAccessibility_SetSoundPitch(actor, 0, 1.0);
//ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_DIAMOND_SWITCH, false);
// ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_DIAMOND_SWITCH, false);
}
void accessible_sticks(AccessibleActor* actor) {
EnKarebaba* baba = (EnKarebaba*)actor->actor;
if (baba->actionFunc != EnKarebaba_DeadItemDrop)
return;
if (actor->actor->flags == 80) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EN_NUTS_DAMAGE, false);
}
}
void accessible_graveyard_soil(AccessibleActor* actor) {
@ -583,7 +558,7 @@ void accessible_graveyard_soil(AccessibleActor* actor) {
void accessible_cucco(AccessibleActor* actor) {
if (actor->actor->params == 14) {
} else if (actor->actor->params == 13) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_CHICKEN_CRY_N, false);
ActorAccessibility_SetSoundPitch(actor, 0, 1.5);
@ -602,40 +577,31 @@ bool accessible_general_helper_init(AccessibleActor* actor) {
actor->userData = data;
return true;
}
void accessible_general_helper_cleanup(AccessibleActor* actor)
{
void accessible_general_helper_cleanup(AccessibleActor* actor) {
free(actor->userData);
actor->userData = NULL;
}
void accessible_va_general_helper(AccessibleActor* actor)
{
void accessible_va_general_helper(AccessibleActor* actor) {
GeneralHelperData* data = (GeneralHelperData*)actor->userData;
if (data->currentScene == actor->play->sceneNum && data->currentRoom != actor->play->roomCtx.curRoom.num)
{
if (data->currentScene == actor->play->sceneNum && data->currentRoom != actor->play->roomCtx.curRoom.num) {
ActorAccessibility_AnnounceRoomNumber(actor->play);
data->currentRoom = actor->play->roomCtx.curRoom.num;
data->currentRoomClear = Flags_GetClear(actor->play, data->currentRoom);
}
if (data->currentScene != actor->play->sceneNum)
{
if (data->currentScene != actor->play->sceneNum) {
ActorAccessibility_InterpretCurrentScene(actor->play);
data->currentScene = actor->play->sceneNum;
data->currentRoom = actor->play->roomCtx.curRoom.num;
data->currentRoomClear = Flags_GetClear(actor->play, data->currentRoom);
}
//Report when a room is completed.
if (!data->currentRoomClear && Flags_GetClear(actor->play, data->currentRoom))
{
// Report when a room is completed.
if (!data->currentRoomClear && Flags_GetClear(actor->play, data->currentRoom)) {
data->currentRoomClear = Flags_GetClear(actor->play, data->currentRoom);
ActorAccessibility_AnnounceRoomNumber(actor->play);
}
}
bool accessible_audio_compass_init(AccessibleActor* actor)
{
bool accessible_audio_compass_init(AccessibleActor* actor) {
AudioCompassData* data = (AudioCompassData*)malloc(sizeof(AudioCompassData));
if (data == NULL)
return false;
@ -644,73 +610,68 @@ bool accessible_audio_compass_init(AccessibleActor* actor)
actor->userData = data;
return true;
}
void accessible_audio_compass_cleanup(AccessibleActor* actor)
{
void accessible_audio_compass_cleanup(AccessibleActor* actor) {
free(actor->userData);
}
void accessible_audio_compass(AccessibleActor* actor) {
Player* player = GET_PLAYER(actor->play);
if (player->stateFlags1 & PLAYER_STATE1_Z_TARGETING || player->stateFlags1 & PLAYER_STATE1_CLIMBING_LADDER)
return;
OSContPad* trackerButtonsPressed = std::dynamic_pointer_cast<LUS::ControlDeck>(Ship::Context::GetInstance()->GetControlDeck())->GetPads();
OSContPad* trackerButtonsPressed =
std::dynamic_pointer_cast<LUS::ControlDeck>(Ship::Context::GetInstance()->GetControlDeck())->GetPads();
AudioCompassData* data = (AudioCompassData*)actor->userData;
bool compassCombo = trackerButtonsPressed != nullptr && trackerButtonsPressed[0].button & buttonList[11] &&
trackerButtonsPressed[0].button & buttonList[6];
actor->world.pos = player->actor.world.pos;
actor->world.pos.z -= 50;
if (data->framesUntilChime > 0)
data->framesUntilChime--;
if (compassCombo && data->framesUntilChime <= 0) {
ActorAccessibility_PlaySoundForActor(actor, 0, actor->policy.sound, false);
data->framesUntilChime = 30;
}
/* Player* player = GET_PLAYER(actor->play);
if (player->stateFlags1 & PLAYER_STATE1_Z_TARGETING || player->stateFlags1 & PLAYER_STATE1_CLIMBING_LADDER)
return;
actor->world.pos = player->actor.world.pos;
actor->world.pos.z -= 50;
bool shouldChime = false;
if (actor->world.rot.y != player->actor.world.rot.y) {
actor->world.rot.y = player->actor.world.rot.y;
if (player->linearVelocity == 0)
shouldChime = true;
}
AudioCompassData* data = (AudioCompassData*)actor->userData;
if (data->linearVelocity == 0.0 && player->linearVelocity > 0.0) {
shouldChime = true;
}
data->linearVelocity = player->linearVelocity;
if (data->framesUntilChime > 0)
data->framesUntilChime--;
if (shouldChime && data->framesUntilChime <= 0) {
/* Player* player = GET_PLAYER(actor->play);
if (player->stateFlags1 & PLAYER_STATE1_Z_TARGETING || player->stateFlags1 & PLAYER_STATE1_CLIMBING_LADDER)
return;
ActorAccessibility_PlaySoundForActor(actor, 0, actor->policy.sound, false);
data->framesUntilChime = 10;
actor->world.pos = player->actor.world.pos;
actor->world.pos.z -= 50;
bool shouldChime = false;
if (actor->world.rot.y != player->actor.world.rot.y) {
actor->world.rot.y = player->actor.world.rot.y;
if (player->linearVelocity == 0)
shouldChime = true;
}
AudioCompassData* data = (AudioCompassData*)actor->userData;
if (data->linearVelocity == 0.0 && player->linearVelocity > 0.0) {
shouldChime = true;
}*/
}
data->linearVelocity = player->linearVelocity;
if (data->framesUntilChime > 0)
data->framesUntilChime--;
if (shouldChime && data->framesUntilChime <= 0) {
ActorAccessibility_PlaySoundForActor(actor, 0, actor->policy.sound, false);
data->framesUntilChime = 10;
}*/
}
void accessible_stick_warning(AccessibleActor* actor) {
Player* player = GET_PLAYER(actor->play);
actor->world.pos = player->actor.world.pos;
actor->world.pos.z -= 50;
if (fabs(player->unk_860 - 25) < 24.0 && player->heldItemId==0) {
if (fabs(player->unk_860 - 25) < 24.0 && player->heldItemId == 0) {
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_SY_WARNING_COUNT_N, false);
}
}
void ActorAccessibility_InitActors() {
void ActorAccessibility_InitActors() {
const int Npc_Frames = 35;
ActorAccessibilityPolicy policy;
ActorAccessibility_InitPolicy(&policy, "Rock", accessible_en_ishi, 0);
@ -826,7 +787,7 @@ void accessible_stick_warning(AccessibleActor* actor) {
policy.distance = 800;
ActorAccessibility_AddSupportedActor(ACTOR_EN_KANBAN, policy);
//ACTOR_EN_A_OBJ has exactly the same configuration.
// ACTOR_EN_A_OBJ has exactly the same configuration.
ActorAccessibility_AddSupportedActor(ACTOR_EN_A_OBJ, policy);
ActorAccessibility_InitPolicy(&policy, "Large Crate", NULL, NA_SE_EV_WOODBOX_BREAK);
ActorAccessibility_AddSupportedActor(ACTOR_OBJ_KIBAKO2, policy);
@ -867,7 +828,7 @@ void accessible_stick_warning(AccessibleActor* actor) {
policy.distance = 2000;
policy.pitch = 1.2;
ActorAccessibility_AddSupportedActor(ACTOR_BG_YDAN_SP, policy);
ActorAccessibility_InitPolicy(&policy, "Shutter Door", accessible_door, 0);
policy.n = 30;
policy.distance = 1000;
@ -881,7 +842,6 @@ void accessible_stick_warning(AccessibleActor* actor) {
policy.n = 1;
policy.ydist = 200;
policy.pitch = 1.1;
ActorAccessibility_AddSupportedActor(ACTOR_OBJ_SWITCH, policy);
ActorAccessibility_InitPolicy(&policy, "Ocarina Spots", NULL, NA_SE_EV_DIAMOND_SWITCH);
@ -902,14 +862,14 @@ void accessible_stick_warning(AccessibleActor* actor) {
policy.distance = 800;
ActorAccessibility_AddSupportedActor(ACTOR_OBJ_SYOKUDAI, policy);
ActorAccessibility_InitPolicy(&policy, "Deku Tree Moving Platform", accessible_hasi, 0);
//policy.volume = 1.3;
// policy.volume = 1.3;
policy.distance = 1000;
ActorAccessibility_AddSupportedActor(ACTOR_BG_YDAN_HASI, policy);
ActorAccessibility_InitPolicy(&policy, "Pot", NULL, NA_SE_EV_POT_BROKEN);
ActorAccessibility_AddSupportedActor(ACTOR_OBJ_TSUBO, policy);
//ActorAccessibility_InitPolicy(&policy, "Deku Tree Entrance", NULL, NA_SE_EV_FANTOM_WARP_L);
//policy.distance = 5000;
//ActorAccessibility_AddSupportedActor(ACTOR_BG_TREEMOUTH, policy);
// ActorAccessibility_InitPolicy(&policy, "Deku Tree Entrance", NULL, NA_SE_EV_FANTOM_WARP_L);
// policy.distance = 5000;
// ActorAccessibility_AddSupportedActor(ACTOR_BG_TREEMOUTH, policy);
ActorAccessibility_InitPolicy(&policy, "Platform collapsable", NULL, NA_SE_EV_BLOCK_SHAKE);
ActorAccessibility_AddSupportedActor(ACTOR_OBJ_LIFT, policy);
ActorAccessibility_InitPolicy(&policy, "Ladder in Slingshot Room", accessible_maruta, 0);
@ -964,29 +924,28 @@ void accessible_stick_warning(AccessibleActor* actor) {
policy.distance = 2000;
ActorAccessibility_AddSupportedActor(VA_CRAWLSPACE, policy);
ActorAccessibility_InitPolicy(&policy, "Ladder/climable", accessible_climable, 0);
//policy.volume = 1.5;
// policy.volume = 1.5;
policy.pitch = 1.3;
//policy.distance = 2000;
// policy.distance = 2000;
ActorAccessibility_AddSupportedActor(VA_CLIMB, policy);
ActorAccessibility_InitPolicy(&policy, "Door", NULL, NA_SE_OC_DOOR_OPEN);
policy.n = 30;
policy.pitch = 1.1;
policy.distance = 1000;
ActorAccessibility_AddSupportedActor(VA_DOOR, policy);
ActorAccessibility_InitPolicy(&policy, "Area Change", accessible_area_change, 0);
policy.n = 60;
policy.distance = 100000;
ActorAccessibility_AddSupportedActor(VA_AREA_CHANGE, policy);
ActorAccessibility_InitPolicy(&policy, "marker", NULL,
NA_SE_EV_DIAMOND_SWITCH);
ActorAccessibility_InitPolicy(&policy, "marker", NULL, NA_SE_EV_DIAMOND_SWITCH);
policy.distance = 1000;
policy.pitch = 1.7;
ActorAccessibility_AddSupportedActor(VA_MARKER, policy);
//ActorAccessibility_InitPolicy(&policy, "Spike", NULL, NA_SE_EV_DIAMOND_SWITCH);
//policy.distance = 200;
//policy.pitch = 0.5;
//ActorAccessibility_AddSupportedActor(VA_SPIKE, policy);
// ActorAccessibility_InitPolicy(&policy, "Spike", NULL, NA_SE_EV_DIAMOND_SWITCH);
// policy.distance = 200;
// policy.pitch = 0.5;
// ActorAccessibility_AddSupportedActor(VA_SPIKE, policy);
ActorAccessibility_InitPolicy(&policy, "Stick Burnout Warning", accessible_stick_warning, 0);
policy.n = 1;
policy.runsAlways = true;
@ -1002,27 +961,27 @@ void accessible_stick_warning(AccessibleActor* actor) {
policy.cleanupUserData = accessible_audio_compass_cleanup;
policy.initUserData = accessible_audio_compass_init;
policy.runsAlways = true;
policy.sound = NA_SE_EV_SHIP_BELL;//Setting this here so it's easy to change if we ever decide to change it.
policy.sound = NA_SE_EV_SHIP_BELL; // Setting this here so it's easy to change if we ever decide to change it.
policy.pitch = 0.5;
ActorAccessibility_AddSupportedActor(VA_AUDIO_COMPASS, policy);
// Now query a list of virtual actors for a given
// location (scene
// and room
// number).
VirtualActorList* list = (VirtualActorList*)ActorAccessibility_GetVirtualActorList(EVERYWHERE, 0);//Global/ omnipresent.
// location (scene
// and room
// number).
VirtualActorList* list =
(VirtualActorList*)ActorAccessibility_GetVirtualActorList(EVERYWHERE, 0); // Global/ omnipresent.
// Now place the actor.
ActorAccessibility_AddVirtualActor(list, VA_GENERAL_HELPER, { { 0.0, 0.0, 0.0 }, { 0, 0, 0 } });
ActorAccessibility_AddVirtualActor(list, VA_AUDIO_COMPASS, { { 0.0, 0.0, 0.0}, { 0, 0, 0 } });
ActorAccessibility_AddVirtualActor(list, VA_AUDIO_COMPASS, { { 0.0, 0.0, 0.0 }, { 0, 0, 0 } });
ActorAccessibility_AddVirtualActor(list, VA_STICK_WARNING, { { 0.0, 0.0, 0.0 }, { 0, 0, 0 } });
list = ActorAccessibility_GetVirtualActorList(85, 0); // Kokiri Forest
ActorAccessibility_AddVirtualActor(list, VA_CRAWLSPACE, { { -784.0, 120.0, 1046.00 }, { 0, 14702, 0 } });
ActorAccessibility_AddVirtualActor(list, VA_MARKER, { { 2146.5, 1.0, -142.8 } });
//ActorAccessibility_AddVirtualActor(list, VA_CLIMB, { { -547.0, 60.0, -1036.00 }, { 0, 14702, 0 } });
//ActorAccessibility_AddVirtualActor(list, VA_CLIMB, { { -29.0, -80.0, 983.00 }, { 0, 14702, 0 } });
// ActorAccessibility_AddVirtualActor(list, VA_CLIMB, { { -547.0, 60.0, -1036.00 }, { 0, 14702, 0 } });
// ActorAccessibility_AddVirtualActor(list, VA_CLIMB, { { -29.0, -80.0, 983.00 }, { 0, 14702, 0 } });
/*ActorAccessibility_AddVirtualActor(list, VA_DOOR, { { -448.0, 0.0, -528.00 }, { 0, 14702, 0 } });
ActorAccessibility_AddVirtualActor(list, VA_DOOR, { { -1082.0, 120.0, 383.00 }, { 0, 14702, 0 } });
ActorAccessibility_AddVirtualActor(list, VA_DOOR, { { -27.0, 100.0, 1117.00 }, { 0, 14702, 0 } });
@ -1030,50 +989,52 @@ void accessible_stick_warning(AccessibleActor* actor) {
ActorAccessibility_AddVirtualActor(list, VA_DOOR, { { 1046.0, 0.0, 549.00 }, { 0, 14702, 0 } });
ActorAccessibility_AddVirtualActor(list, VA_DOOR, { { 848.0, 0.0, -323.00 }, { 0, 14702, 0 } });
*/
//ActorAccessibility_AddVirtualActor(list, VA_AREA_CHANGE,{ { -317.0, 373.2, -1542.00 }, {0, 14702, 0 }}, AREA_KORIRI);
//ActorAccessibility_AddVirtualActor(list, VA_AREA_CHANGE, { { -1380.0, -67.0, -288.00 }, { 0, 14702, 0 } }, AREA_HYRULE_FIELD);
// ActorAccessibility_AddVirtualActor(list, VA_AREA_CHANGE,{ { -317.0, 373.2, -1542.00 }, {0, 14702, 0 }},
// AREA_KORIRI);
// ActorAccessibility_AddVirtualActor(list, VA_AREA_CHANGE, { { -1380.0, -67.0, -288.00 }, { 0, 14702, 0 } },
// AREA_HYRULE_FIELD);
list = ActorAccessibility_GetVirtualActorList(85, 2); // Kokiri Forest Room with boulder and kokiri sword
ActorAccessibility_AddVirtualActor(list, VA_CRAWLSPACE, { { -788.0, 120.0, 1392.00 }, { 0, 14702, 0 } });
//list = ActorAccessibility_GetVirtualActorList(38, 0); //know-it-all house
//ActorAccessibility_AddVirtualActor(list, VA_DOOR, { { 12.0, 0.0, -131.00 }, { 0, 14702, 0 } });
// list = ActorAccessibility_GetVirtualActorList(38, 0); //know-it-all house
// ActorAccessibility_AddVirtualActor(list, VA_DOOR, { { 12.0, 0.0, -131.00 }, { 0, 14702, 0 } });
//list = ActorAccessibility_GetVirtualActorList(40, 0); // mido house
//ActorAccessibility_AddVirtualActor(list, VA_DOOR, { { -6.6, 0.0, -179.00 }, { 0, 14702, 0 } });
// list = ActorAccessibility_GetVirtualActorList(40, 0); // mido house
// ActorAccessibility_AddVirtualActor(list, VA_DOOR, { { -6.6, 0.0, -179.00 }, { 0, 14702, 0 } });
//list = ActorAccessibility_GetVirtualActorList(52, 0); // link's house
//ActorAccessibility_AddVirtualActor(list, VA_DOOR, { { 2.3, 0.0, -134.00 }, { 0, 14702, 0 } });
// list = ActorAccessibility_GetVirtualActorList(52, 0); // link's house
// ActorAccessibility_AddVirtualActor(list, VA_DOOR, { { 2.3, 0.0, -134.00 }, { 0, 14702, 0 } });
//list = ActorAccessibility_GetVirtualActorList(41, 0); // saria's house
//ActorAccessibility_AddVirtualActor(list, VA_DOOR, { { 1.7, 0.0, -188.00 }, { 0, 14702, 0 } });
// list = ActorAccessibility_GetVirtualActorList(41, 0); // saria's house
// ActorAccessibility_AddVirtualActor(list, VA_DOOR, { { 1.7, 0.0, -188.00 }, { 0, 14702, 0 } });
//list = ActorAccessibility_GetVirtualActorList(39, 0); // twins house
//ActorAccessibility_AddVirtualActor(list, VA_DOOR, { { 3.0, 0.0, -179.00 }, { 0, 14702, 0 } });
// list = ActorAccessibility_GetVirtualActorList(39, 0); // twins house
// ActorAccessibility_AddVirtualActor(list, VA_DOOR, { { 3.0, 0.0, -179.00 }, { 0, 14702, 0 } });
//list = ActorAccessibility_GetVirtualActorList(45, 0); // Kokiri Shop
//ActorAccessibility_AddVirtualActor(list, VA_DOOR, { { 0.0, 0.0, 150.00 }, { 0, 14702, 0 } });
// list = ActorAccessibility_GetVirtualActorList(45, 0); // Kokiri Shop
// ActorAccessibility_AddVirtualActor(list, VA_DOOR, { { 0.0, 0.0, 150.00 }, { 0, 14702, 0 } });
list = ActorAccessibility_GetVirtualActorList(0, 0);//deku tree main room
//ActorAccessibility_AddVirtualActor(list, VA_CLIMB, { { -226.7, 0, 197.0 } });
//ActorAccessibility_AddVirtualActor(list, VA_CLIMB, { { 118.6, 0, -286.6 } });
list = ActorAccessibility_GetVirtualActorList(0, 0); // deku tree main room
// ActorAccessibility_AddVirtualActor(list, VA_CLIMB, { { -226.7, 0, 197.0 } });
// ActorAccessibility_AddVirtualActor(list, VA_CLIMB, { { 118.6, 0, -286.6 } });
//ActorAccessibility_AddVirtualActor(list, VA_AREA_CHANGE, { {0, 0, 640} }, AREA_KORIRI);
//ActorAccessibility_AddVirtualActor(list, VA_CLIMB, { { 287.4, 368.0, 347.0 } });
//ActorAccessibility_AddVirtualActor(list, VA_CLIMB, { { 419.4, 368.0, 173.6 } });
//ActorAccessibility_AddVirtualActor(list, VA_CLIMB, { { 323, 567.0, 314.6 } });
//ActorAccessibility_AddVirtualActor(list, VA_CLIMB, { { 127.5, 897.0, 433.6 } });
//ActorAccessibility_AddVirtualActor(list, VA_CLIMB, { { 440.9, 897.0, 101.6 } });
// ActorAccessibility_AddVirtualActor(list, VA_AREA_CHANGE, { {0, 0, 640} }, AREA_KORIRI);
// ActorAccessibility_AddVirtualActor(list, VA_CLIMB, { { 287.4, 368.0, 347.0 } });
// ActorAccessibility_AddVirtualActor(list, VA_CLIMB, { { 419.4, 368.0, 173.6 } });
// ActorAccessibility_AddVirtualActor(list, VA_CLIMB, { { 323, 567.0, 314.6 } });
// ActorAccessibility_AddVirtualActor(list, VA_CLIMB, { { 127.5, 897.0, 433.6 } });
// ActorAccessibility_AddVirtualActor(list, VA_CLIMB, { { 440.9, 897.0, 101.6 } });
list = ActorAccessibility_GetVirtualActorList(0, 2); // deku tree slingshot room
//ActorAccessibility_AddVirtualActor(list, VA_CLIMB, { { -1159, 288.0, 1403.0 } });
//ActorAccessibility_AddVirtualActor(list, VA_CLIMB, { { -1179.6, 480.0, 1463.6 } });
//ActorAccessibility_AddVirtualActor(list, VA_CLIMB, { { -1398.9, 288.0, 1161.6 } });
// ActorAccessibility_AddVirtualActor(list, VA_CLIMB, { { -1159, 288.0, 1403.0 } });
// ActorAccessibility_AddVirtualActor(list, VA_CLIMB, { { -1179.6, 480.0, 1463.6 } });
// ActorAccessibility_AddVirtualActor(list, VA_CLIMB, { { -1398.9, 288.0, 1161.6 } });
list = ActorAccessibility_GetVirtualActorList(0, 10); // deku tree compass room
//ActorAccessibility_AddVirtualActor(list, VA_CLIMB, { { -762, 733.0, 151.0 } });
// ActorAccessibility_AddVirtualActor(list, VA_CLIMB, { { -762, 733.0, 151.0 } });
/*ActorAccessibility_AddVirtualActor(list, VA_MARKER, { { -935, 780.0, -113 } });
ActorAccessibility_AddVirtualActor(list, VA_MARKER, { { -1031.0, 800.0, 109.7 } });
ActorAccessibility_AddVirtualActor(list, VA_MARKER, { { -1184, 820.0, -103.4 } });*/
@ -1084,14 +1045,14 @@ void accessible_stick_warning(AccessibleActor* actor) {
list = ActorAccessibility_GetVirtualActorList(0, 3); // deku tree basement 1 lobby
ActorAccessibility_AddVirtualActor(list, VA_CRAWLSPACE, { { -901, -820.0, 0.5 } });
ActorAccessibility_AddVirtualActor(list, VA_MARKER, { { -181.761, -905.0, -28.3 } });
//ActorAccessibility_AddVirtualActor(list, VA_CLIMB, { { 108, -919.5, 5.0 } });
// ActorAccessibility_AddVirtualActor(list, VA_CLIMB, { { 108, -919.5, 5.0 } });
list = ActorAccessibility_GetVirtualActorList(0, 9); // deku tree b2 lobby
//ActorAccessibility_AddVirtualActor(list, VA_CLIMB, { { -639, -1912.5, 188.0 } });
//Install cues for walls, ledges etc.
list = ActorAccessibility_GetVirtualActorList(1, 2);//dodongo bombflower stairs room
// ActorAccessibility_AddVirtualActor(list, VA_CLIMB, { { -639, -1912.5, 188.0 } });
// Install cues for walls, ledges etc.
list = ActorAccessibility_GetVirtualActorList(1, 2); // dodongo bombflower stairs room
ActorAccessibility_AddVirtualActor(list, VA_MARKER, { { -1958, 20, -1297 } });
list = ActorAccessibility_GetVirtualActorList(69, 0);//hyrule courtyard
list = ActorAccessibility_GetVirtualActorList(69, 0); // hyrule courtyard
ActorAccessibility_AddVirtualActor(list, VA_MARKER, { { 1734.0, 0.0, 140.514 } });
AccessibleActor* temp = ActorAccessibility_AddVirtualActor(list, VA_MARKER, { { 1734.0, 0.0, 140.514 } });
temp->policy.pitch = 0.3;
@ -1117,5 +1078,4 @@ void accessible_stick_warning(AccessibleActor* actor) {
temp->policy.pitch = 1.8;
temp->policy.volume = 0.5;
ActorAccessibility_InitCues();
}

View file

@ -7,11 +7,11 @@
#define AAE_MAX_BUFFER_SIZE AAE_SAMPLE_RATE / 10
#define AAE_PREP_CHUNK_SIZE 64
#define AAE_MIX_CHUNK_SIZE 64
#define AAE_GC_INTERVAL 20 * 60//How often, in frames, do we clean up sound handles that are no longer active.
#define AAE_GC_INTERVAL 20 * 60 // How often, in frames, do we clean up sound handles that are no longer active.
#define AAE_MAX_DB_REDUCTION -20
#define AAE_LPF_ORDER 4
#define NOMINMAX//because Windows is a joke.
#define NOMINMAX // because Windows is a joke.
#include "AccessibleAudioEngine.h"
extern "C" {
@ -25,25 +25,25 @@ enum AAE_COMMANDS {
AAE_STOP,
AAE_STOP_ALL,
AAE_PITCH,
AAE_PITCH_BEHIND,//Specify how much to change the pitch when the sound is behind the listener.
AAE_PITCH_BEHIND, // Specify how much to change the pitch when the sound is behind the listener.
AAE_VOLUME,
AAE_PAN,
AAE_FILTER,
AAE_SEEK,
AAE_LISTENER, //Set the listener's position and direction.
AAE_POS,//Set the sound source's position and direction.
AAE_PREPARE,
AAE_TERMINATE,
AAE_SEEK,
AAE_LISTENER, // Set the listener's position and direction.
AAE_POS, // Set the sound source's position and direction.
AAE_PREPARE,
AAE_TERMINATE,
};
typedef float f32;
typedef int8_t s8;
typedef uint8_t u8;
//Processing for our custom audio positioning.
// Processing for our custom audio positioning.
static float lerp_aae(float x, float y, float z) {
return (1.0 - z) * x + z * y;
}
static float computeGain(SoundExtras * extras) {
static float computeGain(SoundExtras* extras) {
if (extras->maxDistance == 0)
return 0;
float leftover = ma_volume_db_to_linear(AAE_MAX_DB_REDUCTION);
@ -53,23 +53,24 @@ static float lerp_aae(float x, float y, float z) {
gain -= lerp_aae(0, leftover, normDist);
return gain;
}
//Borrow the pan calculation from the game itself. Todo: this is technical debt, so copy/ revise it or something at some point.
extern "C" int8_t Audio_ComputeSoundPanSigned(float x, float z, uint8_t token);
static void positioner_process_pcm_frames(ma_node * pNode, const float** ppFramesIn, ma_uint32* pFrameCountIn,
float** ppFramesOut,
ma_uint32* pFrameCountOut)
{
// Borrow the pan calculation from the game itself. Todo: this is technical debt, so copy/ revise it or something at
// some point.
extern "C" int8_t Audio_ComputeSoundPanSigned(float x, float z, uint8_t token);
static void positioner_process_pcm_frames(ma_node* pNode, const float** ppFramesIn, ma_uint32* pFrameCountIn,
float** ppFramesOut, ma_uint32* pFrameCountOut) {
const float* framesIn = ppFramesIn[0];
float* framesOut = ppFramesOut[0];
ma_copy_pcm_frames(framesOut, framesIn, *pFrameCountIn, ma_format_f32, 2);
*pFrameCountOut = *pFrameCountIn;
SoundExtras* extras = (SoundExtras*)pNode;
//Pan the sound based on its projected position.
// Pan the sound based on its projected position.
float pan;
//Use the game's panning mechanism, which returns a signed 8-bit integer between 0 (far-left) and 127 (far-right).
//It would appear that the correct thing to do is interpret this value as a gain factor in decibels. In practice, values below 38 or above 90 are never seen, so a sound that's panned far to one side or the other amounts to about -25DB worth of attenuation.
//Also: lie about the value of Z and give it a constant value to prevent weird behaviour when Z is far away.
// Use the game's panning mechanism, which returns a signed 8-bit integer between 0 (far-left) and 127 (far-right).
// It would appear that the correct thing to do is interpret this value as a gain factor in decibels. In practice,
// values below 38 or above 90 are never seen, so a sound that's panned far to one side or the other amounts to
// about -25DB worth of attenuation. Also: lie about the value of Z and give it a constant value to prevent weird
// behaviour when Z is far away.
s8 panSigned = Audio_ComputeSoundPanSigned(extras->x, extras->z, 4);
int db;
if (panSigned < 64)
@ -82,36 +83,38 @@ static float lerp_aae(float x, float y, float z) {
ma_panner_set_pan(&extras->panner, pan);
ma_panner_process_pcm_frames(&extras->panner, framesOut, framesOut, *pFrameCountIn);
//Next we'll apply the gain based on the object's distance relationship to the player. The strategy here is to use a combination of decibel-based and linear attenuation, so that the gain reaches 0 at the exact point when the object is at exactly the maximum distance from the player.
// Next we'll apply the gain based on the object's distance relationship to the player. The strategy here is to use
// a combination of decibel-based and linear attenuation, so that the gain reaches 0 at the exact point when the
// object is at exactly the maximum distance from the player.
float gain = computeGain(extras);
ma_gainer_set_gain(&extras->gainer, gain);
ma_gainer_process_pcm_frames(&extras->gainer, framesOut, framesOut, *pFrameCountIn);
//Run LPF only when necessary because we can't afford to run a 4th-order lowpass on every single sound. This probably causes minor glitches when the filter switches on and off. Todo: cross that bridge.
// Run LPF only when necessary because we can't afford to run a 4th-order lowpass on every single sound. This
// probably causes minor glitches when the filter switches on and off. Todo: cross that bridge.
if (extras->cutoff != 1.0)
ma_lpf_process_pcm_frames(&extras->filter, framesOut, framesOut, *pFrameCountIn);
}
ma_lpf_process_pcm_frames(&extras->filter, framesOut, framesOut, *pFrameCountIn);
}
static ma_node_vtable positioner_vtable = {
positioner_process_pcm_frames, NULL, 1, 1, 0};
static ma_node_vtable positioner_vtable = { positioner_process_pcm_frames, NULL, 1, 1, 0 };
static ma_uint32 positioner_channels[1] = { 2 };
void AccessibleAudioEngine::destroy() {
switch (initialized){
case 3:
void AccessibleAudioEngine::destroy() {
switch (initialized) {
case 3:
ma_engine_uninit(&engine);
case 2:
ma_pcm_rb_uninit(&preparedOutput);
case 1:
ma_resource_manager_uninit(&resourceManager);
}
}
}
}
void AccessibleAudioEngine::destroyAndThrow(const char* exceptionText) {
destroy();
throw std::runtime_error(exceptionText);
throw std::runtime_error(exceptionText);
}
uint32_t AccessibleAudioEngine::retrieve(float* buffer, uint32_t nFrames) {
uint32_t AccessibleAudioEngine::retrieve(float* buffer, uint32_t nFrames) {
uint32_t framesAvailable = ma_pcm_rb_available_read(&preparedOutput);
if (nFrames > framesAvailable)
nFrames = framesAvailable;
@ -128,16 +131,13 @@ throw std::runtime_error(exceptionText);
memcpy(buffer, readBuffer, sizeof(float) * framesObtained * AAE_CHANNELS);
buffer += framesObtained * AAE_CHANNELS;
nFrames -= framesObtained;
nFrames -= framesObtained;
ma_pcm_rb_commit_read(&preparedOutput, framesObtained);
}
return ogNFrames;
}
void AccessibleAudioEngine::doPrepare(SoundAction& action)
{
void AccessibleAudioEngine::doPrepare(SoundAction& action) {
framesUntilGC--;
int nFrames = ma_pcm_rb_available_write(&preparedOutput);
if (nFrames <= 0)
@ -145,19 +145,19 @@ void AccessibleAudioEngine::doPrepare(SoundAction& action)
float* chunk;
while (nFrames > 0) {
//This should not loop more than twice.
// This should not loop more than twice.
uint32_t nextChunk = nFrames;
ma_pcm_rb_acquire_write(&preparedOutput, &nextChunk, (void**)&chunk);//Might reduce nextChunk if there isn't enough buffer space available to accommodate the request.
ma_pcm_rb_acquire_write(&preparedOutput, &nextChunk,
(void**)&chunk); // Might reduce nextChunk if there isn't enough buffer space available
// to accommodate the request.
ma_uint64 framesRead = 0;
ma_engine_read_pcm_frames(&engine, chunk, nextChunk, &framesRead);
//Even if we get fewer frames than expected, we should still submit a full buffer of silence.
// Even if we get fewer frames than expected, we should still submit a full buffer of silence.
if (framesRead < nextChunk)
ma_silence_pcm_frames(chunk + (framesRead * 2), (nextChunk - framesRead), ma_format_f32, 2);
ma_pcm_rb_commit_write(&preparedOutput, (uint32_t) nextChunk);
ma_pcm_rb_commit_write(&preparedOutput, (uint32_t)nextChunk);
nFrames -= nextChunk;
}
}
int AccessibleAudioEngine::getSoundActions(SoundAction* dest, int limit) {
std::unique_lock<std::mutex> lock(mtx);
@ -171,9 +171,8 @@ int AccessibleAudioEngine::getSoundActions(SoundAction* dest, int limit) {
limit--;
}
return actionsOut;
}
void AccessibleAudioEngine::postSoundActions(){
void AccessibleAudioEngine::postSoundActions() {
{
std::scoped_lock<std::mutex> lock(mtx);
for (int i = 0; i < nextOutgoingSoundAction; i++)
@ -187,284 +186,263 @@ void AccessibleAudioEngine::postHighPrioritySoundAction(SoundAction& action) {
soundActions.push_front(action);
cv.notify_one();
}
SoundAction& AccessibleAudioEngine::getNextOutgoingSoundAction() {
SoundAction& AccessibleAudioEngine::getNextOutgoingSoundAction() {
if (nextOutgoingSoundAction >= AAE_SOUND_ACTION_BATCH_SIZE)
postSoundActions();
nextOutgoingSoundAction++;
return outgoingSoundActions[nextOutgoingSoundAction - 1];
}
void AccessibleAudioEngine::runThread() {
}
void AccessibleAudioEngine::runThread() {
bool shouldTerminate = false;
SoundAction incomingSoundActions[AAE_SOUND_ACTION_BATCH_SIZE];
while (true) {
SoundAction incomingSoundActions[AAE_SOUND_ACTION_BATCH_SIZE];
while (true) {
processAudioJobs();
if (framesUntilGC <= 0)
garbageCollect();
if (framesUntilGC <= 0)
garbageCollect();
int batchSize = getSoundActions(incomingSoundActions, AAE_SOUND_ACTION_BATCH_SIZE);
for (int i = 0; i < batchSize; i++) {
SoundAction& action = incomingSoundActions[i];
switch (action.command) {
case AAE_TERMINATE:
return;
case AAE_START:
doPlaySound(action);
break;
case AAE_STOP:
doStopSound(action);
break;
case AAE_STOP_ALL:
doStopAllSounds(action);
break;
int batchSize = getSoundActions(incomingSoundActions, AAE_SOUND_ACTION_BATCH_SIZE);
for (int i = 0; i < batchSize; i++) {
SoundAction& action = incomingSoundActions[i];
switch (action.command) {
case AAE_TERMINATE:
return;
case AAE_START:
doPlaySound(action);
break;
case AAE_STOP:
doStopSound(action);
break;
case AAE_STOP_ALL:
doStopAllSounds(action);
break;
case AAE_PITCH:
doSetPitch(action);
break;
case AAE_PITCH_BEHIND:
doSetPitchBehindModifier(action);
break;
case AAE_VOLUME:
doSetVolume(action);
break;
case AAE_PAN:
doSetPan(action);
break;
case AAE_FILTER:
doSetFilter(action);
break;
case AAE_SEEK:
doSeekSound(action);
break;
case AAE_LISTENER:
doSetListenerPos(action);
break;
case AAE_POS:
doSetSoundPos(action);
break;
case AAE_PITCH:
doSetPitch(action);
break;
case AAE_PITCH_BEHIND:
doSetPitchBehindModifier(action);
break;
case AAE_VOLUME:
doSetVolume(action);
break;
case AAE_PAN:
doSetPan(action);
break;
case AAE_FILTER:
doSetFilter(action);
break;
case AAE_SEEK:
doSeekSound(action);
break;
case AAE_LISTENER:
doSetListenerPos(action);
break;
case AAE_POS:
doSetSoundPos(action);
break;
case AAE_PREPARE:
doPrepare(action);
break;
}
case AAE_PREPARE:
doPrepare(action);
break;
}
}
}
}
SoundSlot* AccessibleAudioEngine::findSound(SoundAction& action)
{
SoundSlot* AccessibleAudioEngine::findSound(SoundAction& action) {
if (action.slot < 0 || action.slot >= AAE_SLOTS_PER_HANDLE)
return NULL;
return NULL;
auto i = sounds.find(action.handle);
if (i == sounds.end())
return NULL;
return NULL;
SoundSlot& target = i->second[action.slot];
if (!target.active)
return NULL;
return NULL;
return &target;
}
void AccessibleAudioEngine::doPlaySound(SoundAction& action) {
}
void AccessibleAudioEngine::doPlaySound(SoundAction& action) {
SoundSlot* sound;
if (sounds.contains(action.handle)) {
sound = &sounds[action.handle][action.slot];
if (sound->active) {
ma_sound_stop(&sound->sound);
destroySound(sound);
}
sound = &sounds[action.handle][action.slot];
if (sound->active) {
ma_sound_stop(&sound->sound);
destroySound(sound);
}
}
else {
SoundSlots temp;
for (int i = 0; i < AAE_SLOTS_PER_HANDLE; i++)
temp[i].active = false;
sounds[action.handle] = temp;
temp[i].active = false;
sounds[action.handle] = temp;
sound = &sounds[action.handle][action.slot];
}
if (ma_sound_init_from_file(&engine, action.path.c_str(), MA_SOUND_FLAG_NO_SPATIALIZATION|MA_SOUND_FLAG_NO_DEFAULT_ATTACHMENT, NULL, NULL,
if (ma_sound_init_from_file(&engine, action.path.c_str(),
MA_SOUND_FLAG_NO_SPATIALIZATION | MA_SOUND_FLAG_NO_DEFAULT_ATTACHMENT, NULL, NULL,
&sound->sound) != MA_SUCCESS)
return;
return;
initSoundExtras(sound);
ma_sound_set_looping(&sound->sound, action.looping);
//We actually attach the extras to the engine, not the sound itself.
ma_node_attach_output_bus(&sound->extras, 0, ma_node_graph_get_endpoint(&engine.nodeGraph), 0);
ma_sound_set_looping(&sound->sound, action.looping);
// We actually attach the extras to the engine, not the sound itself.
ma_node_attach_output_bus(&sound->extras, 0, ma_node_graph_get_endpoint(&engine.nodeGraph), 0);
ma_sound_start(&sound->sound);
ma_sound_start(&sound->sound);
sound->active = true;
sound->active = true;
}
void AccessibleAudioEngine::doStopSound(SoundAction& action) {
SoundSlot* slot = findSound(action);
if (slot == NULL)
return;
destroySound(slot);
}
void AccessibleAudioEngine::doStopAllSounds(SoundAction& action) {
auto it = sounds.find(action.handle);
if (it == sounds.end())
return;
SoundSlots& slots = it->second;
for (int i = 0; i < AAE_SLOTS_PER_HANDLE; i++) {
if (slots[i].active)
destroySound(&slots[i]);
}
void AccessibleAudioEngine::doStopSound(SoundAction& action) {
SoundSlot* slot = findSound(action);
if (slot == NULL)
return;
destroySound(slot);
}
void AccessibleAudioEngine::doStopAllSounds(SoundAction& action)
{
auto it = sounds.find(action.handle);
if (it == sounds.end())
return;
SoundSlots& slots = it->second;
for (int i = 0; i < AAE_SLOTS_PER_HANDLE; i++)
{
if (slots[i].active)
destroySound(&slots[i]);
}
sounds.erase(it);
sounds.erase(it);
}
void AccessibleAudioEngine::doSetPitch(SoundAction& action) {
SoundSlot* slot = findSound(action);
if (slot == NULL)
return;
slot->extras.pitch = action.pitch;
float pitch = action.pitch;
if (slot->extras.z < 0)
pitch *= (1.0 - slot->extras.pitchBehindModifier);
ma_sound_set_pitch(&slot->sound, pitch);
}
}
void AccessibleAudioEngine::doSetPitch(SoundAction& action)
{
SoundSlot* slot = findSound(action);
if (slot == NULL)
return;
slot->extras.pitch = action.pitch;
float pitch = action.pitch;
if (slot->extras.z < 0)
pitch *= (1.0 - slot->extras.pitchBehindModifier);
ma_sound_set_pitch(&slot->sound, pitch);
}
void AccessibleAudioEngine::doSetPitchBehindModifier(SoundAction& action)
{
SoundSlot* slot = findSound(action);
if (slot == NULL)
return;
slot->extras.pitchBehindModifier = action.pitch;
}
void AccessibleAudioEngine::doSetVolume(SoundAction& action)
{
SoundSlot* slot = findSound(action);
if (slot == NULL)
return;
ma_sound_set_volume(&slot->sound, action.pitch);
}
void AccessibleAudioEngine::doSetPan(SoundAction& action)
{
SoundSlot* slot = findSound(action);
if (slot == NULL)
return;
ma_sound_set_pan(&slot->sound, action.pan);
}
void AccessibleAudioEngine::doSetFilter(SoundAction& action)
{
SoundSlot* slot = findSound(action);
if (slot == NULL)
return;
slot->extras.cutoff = action.cutoff;
ma_lpf_config config =
ma_lpf_config_init(ma_format_f32, AAE_CHANNELS, AAE_SAMPLE_RATE, lerp_aae(0.0, AAE_SAMPLE_RATE / 2, action.cutoff), AAE_LPF_ORDER);
ma_lpf_reinit(&config, &slot->extras.filter);
}
void AccessibleAudioEngine::doSeekSound(SoundAction& action)
{
SoundSlot* slot = findSound(action);
if (slot == NULL)
return;
ma_sound_seek_to_pcm_frame(&slot->sound, action.offset);
}
void AccessibleAudioEngine::doSetListenerPos(SoundAction& action)
{
}
void AccessibleAudioEngine::doSetSoundPos(SoundAction& action)
{
SoundSlot* slot = findSound(action);
if (slot == NULL)
return;
slot->extras.x = action.posX;
slot->extras.y = action.posY;
slot->extras.z = action.posZ;
slot->extras.distToPlayer = action.distToPlayer;
slot->extras.maxDistance = action.maxDistance;
float pitch = slot->extras.pitch;
if (action.posZ < 0)
pitch *= (1.0 - slot->extras.pitchBehindModifier);
ma_sound_set_pitch(&slot->sound, pitch);
}
void AccessibleAudioEngine::garbageCollect()
{
for (auto i = sounds.begin(); i != sounds.end(); ) {
int deadSlots = 0;
for (int x = 0; x < AAE_SLOTS_PER_HANDLE; x++) {
if (!i->second[x].active)
deadSlots++;
else if (!ma_sound_is_playing(&i->second[x].sound)) {
destroySound(&i->second[x]);
i->second[x].active = false;
deadSlots++;
}
void AccessibleAudioEngine::doSetPitchBehindModifier(SoundAction& action) {
SoundSlot* slot = findSound(action);
if (slot == NULL)
return;
slot->extras.pitchBehindModifier = action.pitch;
}
void AccessibleAudioEngine::doSetVolume(SoundAction& action) {
SoundSlot* slot = findSound(action);
if (slot == NULL)
return;
ma_sound_set_volume(&slot->sound, action.pitch);
}
void AccessibleAudioEngine::doSetPan(SoundAction& action) {
SoundSlot* slot = findSound(action);
if (slot == NULL)
return;
ma_sound_set_pan(&slot->sound, action.pan);
}
void AccessibleAudioEngine::doSetFilter(SoundAction& action) {
SoundSlot* slot = findSound(action);
if (slot == NULL)
return;
slot->extras.cutoff = action.cutoff;
ma_lpf_config config = ma_lpf_config_init(ma_format_f32, AAE_CHANNELS, AAE_SAMPLE_RATE,
lerp_aae(0.0, AAE_SAMPLE_RATE / 2, action.cutoff), AAE_LPF_ORDER);
ma_lpf_reinit(&config, &slot->extras.filter);
}
void AccessibleAudioEngine::doSeekSound(SoundAction& action) {
SoundSlot* slot = findSound(action);
if (slot == NULL)
return;
ma_sound_seek_to_pcm_frame(&slot->sound, action.offset);
}
void AccessibleAudioEngine::doSetListenerPos(SoundAction& action) {
}
void AccessibleAudioEngine::doSetSoundPos(SoundAction& action) {
SoundSlot* slot = findSound(action);
if (slot == NULL)
return;
slot->extras.x = action.posX;
slot->extras.y = action.posY;
slot->extras.z = action.posZ;
slot->extras.distToPlayer = action.distToPlayer;
slot->extras.maxDistance = action.maxDistance;
float pitch = slot->extras.pitch;
if (action.posZ < 0)
pitch *= (1.0 - slot->extras.pitchBehindModifier);
ma_sound_set_pitch(&slot->sound, pitch);
}
void AccessibleAudioEngine::garbageCollect() {
for (auto i = sounds.begin(); i != sounds.end();) {
int deadSlots = 0;
for (int x = 0; x < AAE_SLOTS_PER_HANDLE; x++) {
if (!i->second[x].active)
deadSlots++;
else if (!ma_sound_is_playing(&i->second[x].sound)) {
destroySound(&i->second[x]);
i->second[x].active = false;
deadSlots++;
}
if (deadSlots == AAE_SLOTS_PER_HANDLE) // Entire batch is garbage.
i = sounds.erase(i);
else
i++;
}
framesUntilGC = AAE_GC_INTERVAL;
if (deadSlots == AAE_SLOTS_PER_HANDLE) // Entire batch is garbage.
i = sounds.erase(i);
else
i++;
}
void AccessibleAudioEngine::processAudioJobs()
{
ma_job job;
while (ma_resource_manager_next_job(&resourceManager, &job) == MA_SUCCESS)
ma_job_process(&job);
framesUntilGC = AAE_GC_INTERVAL;
}
void AccessibleAudioEngine::processAudioJobs() {
ma_job job;
while (ma_resource_manager_next_job(&resourceManager, &job) == MA_SUCCESS)
ma_job_process(&job);
}
bool AccessibleAudioEngine::initSoundExtras(SoundSlot* slot) {
ma_node_config config = ma_node_config_init();
config.inputBusCount = 1;
config.outputBusCount = 1;
config.pInputChannels = positioner_channels;
config.pOutputChannels = positioner_channels;
config.vtable = &positioner_vtable;
memset(&slot->extras, 0, sizeof(SoundExtras));
if (ma_node_init(&engine.nodeGraph, &config, NULL, &slot->extras) != MA_SUCCESS)
return false;
ma_panner_config pc = ma_panner_config_init(ma_format_f32, AAE_CHANNELS);
pc.mode = ma_pan_mode_balance;
ma_panner_init(&pc, &slot->extras.panner);
ma_gainer_config gc = ma_gainer_config_init(
AAE_CHANNELS,
AAE_SAMPLE_RATE / 20); // Allow one in-game frame for the gain to work its way towards the target value.
if (ma_gainer_init(&gc, NULL, &slot->extras.gainer) != MA_SUCCESS)
return false;
ma_lpf_config fc =
ma_lpf_config_init(ma_format_f32, AAE_CHANNELS, AAE_SAMPLE_RATE, AAE_SAMPLE_RATE / 2, AAE_LPF_ORDER);
ma_lpf_init(&fc, NULL, &slot->extras.filter);
slot->extras.cutoff = 1.0f;
slot->extras.pitch = 1.0f;
slot->extras.pitchBehindModifier = 0.0f;
// ma_node_attach_output_bus(&slot->sound, 0, &slot->extras.filter, 0);
ma_node_attach_output_bus(&slot->sound, 0, &slot->extras, 0);
return true;
}
void AccessibleAudioEngine::destroySound(SoundSlot* slot) {
ma_node_detach_all_output_buses(&slot->extras);
ma_sound_uninit(&slot->sound);
ma_gainer_uninit(&slot->extras.gainer, NULL);
}
bool AccessibleAudioEngine::initSoundExtras(SoundSlot* slot) {
ma_node_config config = ma_node_config_init();
config.inputBusCount = 1;
config.outputBusCount = 1;
config.pInputChannels = positioner_channels;
config.pOutputChannels = positioner_channels;
config.vtable = &positioner_vtable;
memset(&slot->extras, 0, sizeof(SoundExtras));
if (ma_node_init(&engine.nodeGraph, &config, NULL, &slot->extras) != MA_SUCCESS)
return false;
ma_panner_config pc = ma_panner_config_init(ma_format_f32, AAE_CHANNELS);
pc.mode = ma_pan_mode_balance;
ma_panner_init(&pc, &slot->extras.panner);
ma_gainer_config gc = ma_gainer_config_init(AAE_CHANNELS, AAE_SAMPLE_RATE / 20);//Allow one in-game frame for the gain to work its way towards the target value.
if (ma_gainer_init(&gc, NULL, &slot->extras.gainer) != MA_SUCCESS)
return false;
ma_lpf_config fc = ma_lpf_config_init(ma_format_f32, AAE_CHANNELS, AAE_SAMPLE_RATE, AAE_SAMPLE_RATE / 2, AAE_LPF_ORDER);
ma_lpf_init(&fc, NULL, &slot->extras.filter);
slot->extras.cutoff = 1.0f;
slot->extras.pitch = 1.0f;
slot->extras.pitchBehindModifier = 0.0f;
//ma_node_attach_output_bus(&slot->sound, 0, &slot->extras.filter, 0);
ma_node_attach_output_bus(&slot->sound, 0, &slot->extras, 0);
return true;
slot->active = false;
}
}
void AccessibleAudioEngine::destroySound(SoundSlot* slot) {
ma_node_detach_all_output_buses(&slot->extras);
ma_sound_uninit(&slot->sound);
ma_gainer_uninit(&slot->extras.gainer, NULL);
slot->active = false;
}
AccessibleAudioEngine::AccessibleAudioEngine() {
initialized = 0;
ma_resource_manager_config rmc = ma_resource_manager_config_init();
rmc.decodedChannels = AAE_CHANNELS;
rmc.decodedFormat = ma_format_f32;
rmc.decodedSampleRate = AAE_SAMPLE_RATE;
rmc.flags = MA_RESOURCE_MANAGER_FLAG_NON_BLOCKING;
rmc.jobThreadCount = 0;
if (ma_resource_manager_init(&rmc, &resourceManager) != MA_SUCCESS)
destroyAndThrow("AccessibleAudioEngine: Unable to initialize the resource manager.");
initialized = 1;
if (ma_pcm_rb_init(ma_format_f32, AAE_CHANNELS, AAE_MAX_BUFFER_SIZE, NULL, NULL, &preparedOutput) != MA_SUCCESS)
destroyAndThrow("AccessibleAudioEngine: Unable to initialize the output buffer.");
initialized = 2;
ma_engine_config ec = ma_engine_config_init();
AccessibleAudioEngine::AccessibleAudioEngine() {
initialized = 0;
ma_resource_manager_config rmc = ma_resource_manager_config_init();
rmc.decodedChannels = AAE_CHANNELS;
rmc.decodedFormat = ma_format_f32;
rmc.decodedSampleRate = AAE_SAMPLE_RATE;
rmc.flags = MA_RESOURCE_MANAGER_FLAG_NON_BLOCKING;
rmc.jobThreadCount = 0;
if (ma_resource_manager_init(&rmc, &resourceManager) != MA_SUCCESS)
destroyAndThrow("AccessibleAudioEngine: Unable to initialize the resource manager.");
initialized = 1;
if (ma_pcm_rb_init(ma_format_f32, AAE_CHANNELS, AAE_MAX_BUFFER_SIZE, NULL, NULL, &preparedOutput) != MA_SUCCESS)
destroyAndThrow("AccessibleAudioEngine: Unable to initialize the output buffer.");
initialized = 2;
ma_engine_config ec = ma_engine_config_init();
ec.channels = AAE_CHANNELS;
ec.noDevice = true;
ec.sampleRate = AAE_SAMPLE_RATE;
@ -477,152 +455,150 @@ void AccessibleAudioEngine::postHighPrioritySoundAction(SoundAction& action) {
nextOutgoingSoundAction = 0;
framesUntilGC = AAE_GC_INTERVAL;
thread = std::thread(&AccessibleAudioEngine::runThread, this);
}
AccessibleAudioEngine::~AccessibleAudioEngine() {
//Place a terminate command on the top of the pile, then wait for thread to die.
SoundAction action;
action.command = AAE_TERMINATE;
postHighPrioritySoundAction(action);
thread.join();
destroy();
}
void AccessibleAudioEngine::mix(int16_t * ogBuffer, uint32_t nFrames) {
uint32_t framesAvailable = ma_pcm_rb_available_read(&preparedOutput);
float sourceChunk[AAE_MIX_CHUNK_SIZE * AAE_CHANNELS];
float mixedChunk[AAE_MIX_CHUNK_SIZE * AAE_CHANNELS];
while (nFrames > 0) {
uint32_t nextChunk = std::min <uint32_t> (AAE_MIX_CHUNK_SIZE, nFrames);
ma_silence_pcm_frames(sourceChunk, nextChunk, ma_format_f32, AAE_CHANNELS);//This is so that it doesn't matter if we have less output available than expected.
ma_silence_pcm_frames(mixedChunk, nextChunk, ma_format_f32, AAE_CHANNELS);
retrieve(sourceChunk, nextChunk);
ma_pcm_s16_to_f32(mixedChunk, ogBuffer, nextChunk * AAE_CHANNELS, ma_dither_mode_none);//The game's output is changed to 32-bit floating point samples.
ma_mix_pcm_frames_f32(mixedChunk, sourceChunk, nextChunk, AAE_CHANNELS, 1.0);
//If we've gone over 1.0, we'll need to scale back before we go back to 16-bit or we'll distort.
float scalar = 1.0;
}
AccessibleAudioEngine::~AccessibleAudioEngine() {
// Place a terminate command on the top of the pile, then wait for thread to die.
SoundAction action;
action.command = AAE_TERMINATE;
postHighPrioritySoundAction(action);
thread.join();
destroy();
}
void AccessibleAudioEngine::mix(int16_t* ogBuffer, uint32_t nFrames) {
uint32_t framesAvailable = ma_pcm_rb_available_read(&preparedOutput);
float sourceChunk[AAE_MIX_CHUNK_SIZE * AAE_CHANNELS];
float mixedChunk[AAE_MIX_CHUNK_SIZE * AAE_CHANNELS];
while (nFrames > 0) {
uint32_t nextChunk = std::min<uint32_t>(AAE_MIX_CHUNK_SIZE, nFrames);
ma_silence_pcm_frames(
sourceChunk, nextChunk, ma_format_f32,
AAE_CHANNELS); // This is so that it doesn't matter if we have less output available than expected.
ma_silence_pcm_frames(mixedChunk, nextChunk, ma_format_f32, AAE_CHANNELS);
retrieve(sourceChunk, nextChunk);
ma_pcm_s16_to_f32(mixedChunk, ogBuffer, nextChunk * AAE_CHANNELS,
ma_dither_mode_none); // The game's output is changed to 32-bit floating point samples.
ma_mix_pcm_frames_f32(mixedChunk, sourceChunk, nextChunk, AAE_CHANNELS, 1.0);
// If we've gone over 1.0, we'll need to scale back before we go back to 16-bit or we'll distort.
float scalar = 1.0;
for (int i = 0; i < nextChunk * AAE_CHANNELS; i++)
scalar = std::max(scalar, mixedChunk[i]);
if (scalar > 1.0) {
scalar = 1.0 / scalar;
for (int i = 0; i < nextChunk * AAE_CHANNELS; i++)
scalar = std::max(scalar, mixedChunk[i]);
if (scalar > 1.0) {
scalar = 1.0 / scalar;
for (int i = 0; i < nextChunk * AAE_CHANNELS; i++)
mixedChunk[i] *= scalar;
}
ma_pcm_f32_to_s16(ogBuffer, mixedChunk, nextChunk * AAE_CHANNELS, ma_dither_mode_triangle);//Chunk is ready to go out via the game's usual channels.
ogBuffer += nextChunk * AAE_CHANNELS;
nFrames -= nextChunk;
}
mixedChunk[i] *= scalar;
}
ma_pcm_f32_to_s16(ogBuffer, mixedChunk, nextChunk * AAE_CHANNELS,
ma_dither_mode_triangle); // Chunk is ready to go out via the game's usual channels.
ogBuffer += nextChunk * AAE_CHANNELS;
nFrames -= nextChunk;
}
}
void AccessibleAudioEngine::playSound(uintptr_t handle, int slot, const char* path, bool looping) {
if (slot < 0 || slot >= AAE_SLOTS_PER_HANDLE)
return;
SoundAction& action = getNextOutgoingSoundAction();
return;
SoundAction& action = getNextOutgoingSoundAction();
action.handle = handle;
action.slot = slot;
action.command = AAE_START;
action.slot = slot;
action.command = AAE_START;
action.path = path;
action.looping = looping;
}
action.looping = looping;
}
void AccessibleAudioEngine::stopSound(uintptr_t handle, int slot) {
if (slot < 0 || slot >= AAE_SLOTS_PER_HANDLE)
return;
SoundAction& action = getNextOutgoingSoundAction();
action.command = AAE_STOP;
action.handle = (uintptr_t) handle;
action.slot = slot;
}
if (slot < 0 || slot >= AAE_SLOTS_PER_HANDLE)
return;
SoundAction& action = getNextOutgoingSoundAction();
action.command = AAE_STOP;
action.handle = (uintptr_t)handle;
action.slot = slot;
}
void AccessibleAudioEngine::stopAllSounds(uintptr_t handle) {
SoundAction& action = getNextOutgoingSoundAction();
action.command = AAE_STOP_ALL;
action.handle = handle;
}
void AccessibleAudioEngine::setPitch(uintptr_t handle, int slot, float pitch) {
if (slot < 0 || slot >= AAE_SLOTS_PER_HANDLE)
return;
SoundAction& action = getNextOutgoingSoundAction();
action.command = AAE_STOP_ALL;
action.handle = handle;
}
void AccessibleAudioEngine::setPitch(uintptr_t handle, int slot, float pitch) {
if (slot < 0 || slot >= AAE_SLOTS_PER_HANDLE)
return;
SoundAction& action = getNextOutgoingSoundAction();
action.command = AAE_PITCH;
action.handle = handle;
action.slot = slot;
action.pitch = pitch;
SoundAction& action = getNextOutgoingSoundAction();
action.command = AAE_PITCH;
action.handle = handle;
action.slot = slot;
action.pitch = pitch;
}
void AccessibleAudioEngine::setPitchBehindModifier(uintptr_t handle, int slot, float mod) {
if (slot < 0 || slot >= AAE_SLOTS_PER_HANDLE)
return;
}
void AccessibleAudioEngine::setPitchBehindModifier(uintptr_t handle, int slot, float mod) {
if (slot < 0 || slot >= AAE_SLOTS_PER_HANDLE)
return;
SoundAction& action = getNextOutgoingSoundAction();
action.command = AAE_PITCH_BEHIND;
action.handle = handle;
action.slot = slot;
action.pitch = mod;
}
SoundAction& action = getNextOutgoingSoundAction();
action.command = AAE_PITCH_BEHIND;
action.handle = handle;
action.slot = slot;
action.pitch = mod;
void AccessibleAudioEngine::setVolume(uintptr_t handle, int slot, float volume) {
}
void AccessibleAudioEngine::setVolume(uintptr_t handle, int slot, float volume) {
if (slot < 0 || slot >= AAE_SLOTS_PER_HANDLE)
return;
SoundAction& action = getNextOutgoingSoundAction();
action.command = AAE_VOLUME;
action.handle = handle;
action.slot = slot;
action.volume = volume;
}
if (slot < 0 || slot >= AAE_SLOTS_PER_HANDLE)
return;
SoundAction& action = getNextOutgoingSoundAction();
action.command = AAE_VOLUME;
action.handle = handle;
action.slot = slot;
action.volume = volume;
}
void AccessibleAudioEngine::setPan(uintptr_t handle, int slot, float pan) {
if (slot < 0 || slot >= AAE_SLOTS_PER_HANDLE)
return;
SoundAction& action = getNextOutgoingSoundAction();
action.command = AAE_PAN;
action.handle = handle;
action.slot = slot;
action.pan = pan;
}
if (slot < 0 || slot >= AAE_SLOTS_PER_HANDLE)
return;
SoundAction& action = getNextOutgoingSoundAction();
action.command = AAE_PAN;
action.handle = handle;
action.slot = slot;
action.pan = pan;
}
void AccessibleAudioEngine::setFilter(uintptr_t handle, int slot, float cutoff) {
if (slot < 0 || slot >= AAE_SLOTS_PER_HANDLE)
return;
if (cutoff < 0.0 || cutoff > 1.0)
return;
SoundAction& action = getNextOutgoingSoundAction();
action.handle = handle;
action.slot = slot;
action.command = AAE_FILTER;
action.cutoff = cutoff;
}
void AccessibleAudioEngine::seekSound(uintptr_t handle, int slot, size_t offset) {
if (slot < 0 || slot >= AAE_SLOTS_PER_HANDLE)
return;
SoundAction& action = getNextOutgoingSoundAction();
action.handle = handle;
action.slot = slot;
action.command = AAE_SEEK;
action.offset = offset;
if (slot < 0 || slot >= AAE_SLOTS_PER_HANDLE)
return;
if (cutoff < 0.0 || cutoff > 1.0)
return;
SoundAction& action = getNextOutgoingSoundAction();
action.handle = handle;
action.slot = slot;
action.command = AAE_FILTER;
action.cutoff = cutoff;
}
void AccessibleAudioEngine::setSoundPosition(uintptr_t handle, int slot, float posX, float posY, float posZ, float distToPlayer, float maxDistance) {
if (slot < 0 || slot >= AAE_SLOTS_PER_HANDLE)
return;
SoundAction& action = getNextOutgoingSoundAction();
action.command = AAE_POS;
action.handle = handle;
action.slot = slot;
action.posX = posX;
action.posY = posY;
action.posZ = posZ;
action.distToPlayer = distToPlayer;
action.maxDistance = maxDistance;
void AccessibleAudioEngine::seekSound(uintptr_t handle, int slot, size_t offset) {
if (slot < 0 || slot >= AAE_SLOTS_PER_HANDLE)
return;
SoundAction& action = getNextOutgoingSoundAction();
action.handle = handle;
action.slot = slot;
action.command = AAE_SEEK;
action.offset = offset;
}
void AccessibleAudioEngine::setSoundPosition(uintptr_t handle, int slot, float posX, float posY, float posZ,
float distToPlayer, float maxDistance) {
if (slot < 0 || slot >= AAE_SLOTS_PER_HANDLE)
return;
SoundAction& action = getNextOutgoingSoundAction();
action.command = AAE_POS;
action.handle = handle;
action.slot = slot;
action.posX = posX;
action.posY = posY;
action.posZ = posZ;
action.distToPlayer = distToPlayer;
action.maxDistance = maxDistance;
}
void AccessibleAudioEngine::prepare() {
SoundAction& action = getNextOutgoingSoundAction();
action.command = AAE_PREPARE;
// This is called once at the end of every frame, so now is the time to post all of the accumulated commands.
postSoundActions();
}
void AccessibleAudioEngine::prepare() {
SoundAction& action = getNextOutgoingSoundAction();
action.command = AAE_PREPARE;
//This is called once at the end of every frame, so now is the time to post all of the accumulated commands.
postSoundActions();
}
void AccessibleAudioEngine::cacheDecodedSample(std::string& path, void* data, size_t size) {
//The data is stored in wave format, so we register it with MiniAudio as an encoded asset as opposed to a decoded one.
ma_resource_manager_register_encoded_data(&resourceManager, path.c_str(), data, size);
}
// The data is stored in wave format, so we register it with MiniAudio as an encoded asset as opposed to a decoded
// one.
ma_resource_manager_register_encoded_data(&resourceManager, path.c_str(), data, size);
}

View file

@ -13,90 +13,91 @@
#define AAE_SLOTS_PER_HANDLE 10
class IResource;
struct DecodedSample {
void* data;//A wav file.
void* data; // A wav file.
size_t dataSize;
};
struct SoundAction {
uintptr_t handle; // This handle is user-defined and uniquely identifies a sound source. It can be anything, but the
// address of an object with which the sound is associated is recommended.
int slot;//Allows multiple sounds per handle. The exact number is controlled by AAE_SOUNDS_PER_HANDLE.
int command; // One of the items belonging to AAE_COMMANDS.
// address of an object with which the sound is associated is recommended.
int slot; // Allows multiple sounds per handle. The exact number is controlled by AAE_SOUNDS_PER_HANDLE.
int command; // One of the items belonging to AAE_COMMANDS.
std::string path; // If command is AAE_START, this is the path to the desired resource.
bool looping; // If command is AAE_START, specifies whether or not the sound should loop.
union {
float pitch;
float volume;
float pan;
float cutoff;
size_t offset;//for seeking.
float distance;
};
union {
float pitch;
float volume;
float pan;
float cutoff;
size_t offset; // for seeking.
float distance;
};
//Position and rotation vectors for AAE_LISTENER and AAE_POS.
float posX;
float posY;
float posZ;
float distToPlayer;
float maxDistance;
uint32_t frames; // If command is AAE_PREPARE, this tells the engine how many PCM frames to get ready.
// Position and rotation vectors for AAE_LISTENER and AAE_POS.
float posX;
float posY;
float posZ;
float distToPlayer;
float maxDistance;
uint32_t frames; // If command is AAE_PREPARE, this tells the engine how many PCM frames to get ready.
};
typedef struct
{
ma_node_base base;
ma_panner panner;
ma_gainer gainer;
ma_lpf filter;
float cutoff;
float x;
float y;
float z;
float distToPlayer;
float maxDistance;
float pitch;
float pitchBehindModifier;
}SoundExtras;//Used for attenuation and other effects.
typedef struct {
ma_node_base base;
ma_panner panner;
ma_gainer gainer;
ma_lpf filter;
float cutoff;
float x;
float y;
float z;
float distToPlayer;
float maxDistance;
float pitch;
float pitchBehindModifier;
} SoundExtras; // Used for attenuation and other effects.
typedef struct
{
ma_sound sound;
SoundExtras extras;
typedef struct {
ma_sound sound;
SoundExtras extras;
bool active;
}SoundSlot;
bool active;
} SoundSlot;
typedef std::array<SoundSlot, AAE_SLOTS_PER_HANDLE> SoundSlots;
class AccessibleAudioEngine {
int initialized;
ma_resource_manager resourceManager;
ma_engine engine;
ma_pcm_rb preparedOutput;//Lock-free single producer single consumer.
std::deque <SoundAction> soundActions;//A command cue.
ma_pcm_rb preparedOutput; // Lock-free single producer single consumer.
std::deque<SoundAction> soundActions; // A command cue.
std::thread thread;
std::condition_variable cv;
std::mutex mtx;
std::unordered_map<uintptr_t, SoundSlots> sounds;
SoundAction outgoingSoundActions[AAE_SOUND_ACTION_BATCH_SIZE];//Allows batch delivery of SoundActions to the FIFO to minimize the amount of time spent locking and unlocking.
SoundAction
outgoingSoundActions[AAE_SOUND_ACTION_BATCH_SIZE]; // Allows batch delivery of SoundActions to the FIFO to
// minimize the amount of time spent locking and unlocking.
int nextOutgoingSoundAction;
int framesUntilGC;
void destroy();//Called by the destructor, or if a throw occurs during construction.
//Dismantal a partial initialization and throw an exception.
void destroyAndThrow(const char* exceptionText);
void destroy(); // Called by the destructor, or if a throw occurs during construction.
// Dismantal a partial initialization and throw an exception.
void destroyAndThrow(const char* exceptionText);
//Retrieve some audio from the output buffer. This is to be performed by the audio thread. May return less data than requested.
// Retrieve some audio from the output buffer. This is to be performed by the audio thread. May return less data
// than requested.
uint32_t retrieve(float* buffer, uint32_t nFrames);
//Functions dealing with the command queue.
// Functions dealing with the command queue.
int getSoundActions(SoundAction* dest, int limit);
void postSoundActions();
void postHighPrioritySoundAction(SoundAction& action);//For now this is used only for termination events.
void postHighPrioritySoundAction(SoundAction& action); // For now this is used only for termination events.
SoundAction& getNextOutgoingSoundAction();
void runThread();
//Find a sound by handle and slot, if it exists.
SoundSlot* findSound(SoundAction& action);
// Find a sound by handle and slot, if it exists.
SoundSlot* findSound(SoundAction& action);
//Functions which correspond to SoundAction commands.
//Ready a sound for playback.
// Functions which correspond to SoundAction commands.
// Ready a sound for playback.
void doPlaySound(SoundAction& action);
void doStopSound(SoundAction& action);
void doStopAllSounds(SoundAction& action);
@ -113,37 +114,39 @@ SoundSlot* findSound(SoundAction& action);
// Generate some output, and store it in the output buffer for later retrieval. May generate less output than
// requested if buffer space is insufficient.
void doPrepare(SoundAction& action);
//Run every so often to clean up expired sound handles.
// Run every so often to clean up expired sound handles.
void garbageCollect();
//Run MiniAudio's jobs.
// Run MiniAudio's jobs.
void processAudioJobs();
//Set up the panner and other effect processing on a sound slot.
// Set up the panner and other effect processing on a sound slot.
bool initSoundExtras(SoundSlot* slot);
void destroySound(SoundSlot* slot);
public:
AccessibleAudioEngine();
~AccessibleAudioEngine();
//Mix the game's audio with this engine's audio to produce the final mix. To be performed exclusively in the audio thread. Mixing is done in-place (meaning the buffer containing the game's audio is overwritten with the mixed content).
// Mix the game's audio with this engine's audio to produce the final mix. To be performed exclusively in the audio
// thread. Mixing is done in-place (meaning the buffer containing the game's audio is overwritten with the mixed
// content).
void mix(int16_t* ogBuffer, uint32_t nFrames);
//Start playing a sound.
// Start playing a sound.
void playSound(uintptr_t handle, int slot, const char* path, bool looping);
void stopSound(uintptr_t handle, int slot);
//Stop all sounds belonging to a handle.
// Stop all sounds belonging to a handle.
void stopAllSounds(uintptr_t handle);
void setPitch(uintptr_t handle, int slot, float pitch);
void setPitchBehindModifier(uintptr_t handle, int slot, float mod);
void setVolume(uintptr_t handle, int slot, float volume);
void setPan(uintptr_t handle, int slot, float pan);
//Set the lowpass filter cutoff. Set to 1.0 for no filtering.
void setFilter(uintptr_t handle, int slot, float cutoff);
//Seek the sound to a particular PCM frame.
// Set the lowpass filter cutoff. Set to 1.0 for no filtering.
void setFilter(uintptr_t handle, int slot, float cutoff);
// Seek the sound to a particular PCM frame.
void seekSound(uintptr_t handle, int slot, size_t offset);
void setSoundPosition(uintptr_t handle, int slot, float posX, float posY, float posZ, float distToPlayer, float maxDistance);
//Schedule the preparation of output for delivery.
void setSoundPosition(uintptr_t handle, int slot, float posX, float posY, float posZ, float distToPlayer,
float maxDistance);
// Schedule the preparation of output for delivery.
void prepare();
void cacheDecodedSample(std::string& path, void* data, size_t size);
};
#endif

File diff suppressed because it is too large Load diff

View file

@ -4,7 +4,9 @@
#ifdef __cplusplus
extern "C" {
#endif
#define NUM_MANAGED_SOUND_SLOTS 10 //How many auto-managed sound slots can any given actor have? this can differ from AAE_SLOTS_PER_HANDLE, but cannot be greater.
#define NUM_MANAGED_SOUND_SLOTS \
10 // How many auto-managed sound slots can any given actor have? this can differ from AAE_SLOTS_PER_HANDLE, but
// cannot be greater.
struct AccessibleActor;
typedef struct AccessibleActor AccessibleActor;
// A callback that is run regularely as the game progresses in order to provide accessibility services for an actor.
@ -28,20 +30,20 @@ typedef struct {
int n; // How often to run the callback in frames.
f32 distance; // Maximum xz distance from player before the actor should be considered out of range.
f32 ydist; // Maximum y distance from player before the actor should be considered out of range.
f32 ydist; // Maximum y distance from player before the actor should be considered out of range.
f32 pitch;
f32 volume;
f32 pitchModifier;
bool runsAlways; // If set, then the distance policy is ignored.
ActorAccessibilityUserDataInit initUserData;
ActorAccessibilityUserDataCleanup cleanupUserData;
//Aim assist settings.
// Aim assist settings.
struct {
bool isProvider;//determines whether or not this actor supports aim assist.
s16 sfx; // The sound to play when this actor provides aim assist. Uses sound slot 9.
f32 tolerance; // How close to the center of the actor does Link have to aim for aim assist to consider
// it lined up.
}aimAssist;
bool isProvider; // determines whether or not this actor supports aim assist.
s16 sfx; // The sound to play when this actor provides aim assist. Uses sound slot 9.
f32 tolerance; // How close to the center of the actor does Link have to aim for aim assist to consider
// it lined up.
} aimAssist;
} ActorAccessibilityPolicy;
@ -71,8 +73,10 @@ struct AccessibleActor {
f32 basePitch;
f32 currentPitch;
s16 sceneIndex;//If this actor represents a scene transition, then this will contain the destination scene index. Zero otherwise.
bool managedSoundSlots[NUM_MANAGED_SOUND_SLOTS];//These have their attenuation and panning parameters updated every frame automatically.
s16 sceneIndex; // If this actor represents a scene transition, then this will contain the destination scene index.
// Zero otherwise.
bool managedSoundSlots[NUM_MANAGED_SOUND_SLOTS]; // These have their attenuation and panning parameters updated
// every frame automatically.
struct {
u16 framesSinceAimAssist; // Allows rate-based vertical aim assist. Incremented every frame for aim assist
// actors. Manually reset by aim assist provider.
@ -99,22 +103,25 @@ void ActorAccessibility_AddSupportedActor(s16 type, ActorAccessibilityPolicy pol
void ActorAccessibility_RunAccessibilityForActor(PlayState* play, AccessibleActor* actor);
void ActorAccessibility_RunAccessibilityForAllActors(PlayState* play);
/*
*Play sounds (usually from the game) using the external sound engine. This is probably not the function you want to call most of the time (see below).
* handle: pointer to an arbitrary object. This object can be anything as it's only used as a classifier, but it's recommended that you use an AccessibleActor* as your handle whenever possible. Using AccessibleActor* as the handle gives you automatic cleanup when the actor is killed.
* slot: Allows multiple sounds to be assigned to a single handle. The maximum number of slots per actor is 10 by default (but can be controlled by modifying AAE_SLOTS_PER_HANDLE).
* sfxId: one of the game's sfx IDs. Note that this plays prerendered sounds which you must have previously prepared.
*looping: whether to play the sound just once or on a continuous loop.
*/
*Play sounds (usually from the game) using the external sound engine. This is probably not the function you want to
*call most of the time (see below). handle: pointer to an arbitrary object. This object can be anything as it's only
*used as a classifier, but it's recommended that you use an AccessibleActor* as your handle whenever possible. Using
*AccessibleActor* as the handle gives you automatic cleanup when the actor is killed. slot: Allows multiple sounds to
*be assigned to a single handle. The maximum number of slots per actor is 10 by default (but can be controlled by
*modifying AAE_SLOTS_PER_HANDLE). sfxId: one of the game's sfx IDs. Note that this plays prerendered sounds which you
*must have previously prepared. looping: whether to play the sound just once or on a continuous loop.
*/
void ActorAccessibility_PlaySound(void* actor, int slot, s16 sfxId, bool looping);
//Play one of the game's internal samples.
void ActorAccessibility_PlayRawSample(void* handle, int slot, const char* name, bool looping);
//
//Stop a sound. Todo: consider making this a short fade instead of just cutting it off.
// Play one of the game's internal samples.
void ActorAccessibility_PlayRawSample(void* handle, int slot, const char* name, bool looping);
//
// Stop a sound. Todo: consider making this a short fade instead of just cutting it off.
void ActorAccessibility_StopSound(void* handle, int slot);
void ActorAccessibility_StopAllSounds(void* handle);
void ActorAccessibility_SetSoundPitch(void* handle, int slot, float pitch);
//When we don't have access to something super fancy (such as HRTF), blind-accessible games generally use a change in pitch to tell the player that an object is behind the player.
// When we don't have access to something super fancy (such as HRTF), blind-accessible games generally use a change in
// pitch to tell the player that an object is behind the player.
void ActorAccessibility_SetPitchBehindModifier(void* handle, int slot, float mod);
void ActorAccessibility_SetListenerPos(Vec3f* pos, Vec3f* rot);
@ -125,18 +132,19 @@ void ActorAccessibility_SetSoundPan(void* handle, int slot, Vec3f* projectedPos)
void ActorAccessibility_SetSoundFilter(void* handle, int slot, float cutoff);
void ActorAccessibility_SeekSound(void* handle, int slot, size_t offset);
/*
* Play a sound on behalf of an AccessibleActor.
* This version includes automatic sound management: pitch, panning and attenuation parameters will be updated automatically based on the actor's position.
*
*/
/*
* Play a sound on behalf of an AccessibleActor.
* This version includes automatic sound management: pitch, panning and attenuation parameters will be updated
* automatically based on the actor's position.
*
*/
void ActorAccessibility_PlaySoundForActor(AccessibleActor* actor, int slot, s16 sfxId, bool looping);
void ActorAccessibility_PlaySampleForActor(AccessibleActor* actor, int slot, const char* name, bool looping);
void ActorAccessibility_StopSoundForActor(AccessibleActor* actor, int slot);
void ActorAccessibility_StopAllSoundsForActor(AccessibleActor* actor);
f32 ActorAccessibility_ComputeCurrentVolume(f32 maxDistance, f32 xzDistToPlayer);
// Computes a relative angle based on Link's (or some other actor's) current angle.
// Computes a relative angle based on Link's (or some other actor's) current angle.
Vec3s ActorAccessibility_ComputeRelativeAngle(Vec3s* origin, Vec3s* offset);
void ActorAccessibility_InitCues();
// Stuff related to lists of virtual actors.
@ -153,38 +161,37 @@ typedef enum {
VA_MARKER,
VA_SPIKE,
VA_GENERAL_HELPER, // Room announcements, action icon and other misc help.
VA_AUDIO_COMPASS,//Points north.
VA_STICK_WARNING,//beep when stick is about to burn out.
VA_AUDIO_COMPASS, // Points north.
VA_STICK_WARNING, // beep when stick is about to burn out.
VA_FINAL,
} VIRTUAL_ACTOR_TABLE;
#define EVERYWHERE -32768 // Denotes a virtual actor that is global/ omnipresent.
// Get the list of virtual actors for a given scene and room index.
VirtualActorList* ActorAccessibility_GetVirtualActorList(s16 sceneNum, s8 roomNum);
AccessibleActor* ActorAccessibility_AddVirtualActor(VirtualActorList* list, VIRTUAL_ACTOR_TABLE type, PosRot where);
//Parses the loaded seen and converts select polygons (like ladders, spikes and scene exits) into virtual actors.
// Parses the loaded seen and converts select polygons (like ladders, spikes and scene exits) into virtual actors.
void ActorAccessibility_InterpretCurrentScene(PlayState* play);
//Convert a collision polygon into a virtual actor.
void ActorAccessibility_PolyToVirtualActor(PlayState* play, CollisionPoly* poly, VIRTUAL_ACTOR_TABLE va, VirtualActorList* destination);
//Report which room of a dungeon the player is in.
void ActorAccessibility_AnnounceRoomNumber(PlayState* play);
//Aim cue support.
void ActorAccessibility_ProvideAimAssistForActor(AccessibleActor* actor);
// External audio engine stuff.
// Convert a collision polygon into a virtual actor.
void ActorAccessibility_PolyToVirtualActor(PlayState* play, CollisionPoly* poly, VIRTUAL_ACTOR_TABLE va,
VirtualActorList* destination);
// Report which room of a dungeon the player is in.
void ActorAccessibility_AnnounceRoomNumber(PlayState* play);
// Aim cue support.
void ActorAccessibility_ProvideAimAssistForActor(AccessibleActor* actor);
// External audio engine stuff.
// Initialize the accessible audio engine.
bool ActorAccessibility_InitAudio();
void ActorAccessibility_ShutdownAudio();
// Combine the games' audio with the output from AccessibleAudioEngine. To be called exclusively from the audio thread.
void ActorAccessibility_MixAccessibleAudioWithGameAudio(int16_t* ogBuffer, uint32_t nFrames);
void ActorAccessibility_HandleSoundExtractionMode(PlayState* play);
//This is called by the audio thread when it's ready to try to pull sfx from the game.
// This is called by the audio thread when it's ready to try to pull sfx from the game.
void ActorAccessibility_DoSoundExtractionStep();
void ActorAccessibility_AudioGlossary(PlayState* play);
#ifdef __cplusplus
}

View file

@ -92,13 +92,13 @@ void SfxExtractor::renderOutput() {
void SfxExtractor::setup() {
try {
SpeechSynthesizer::Instance->Speak("Sfx extraction speedrun initiated. Please wait. This will take a few minutes.", GetLanguageCode());
SpeechSynthesizer::Instance->Speak(
"Sfx extraction speedrun initiated. Please wait. This will take a few minutes.", GetLanguageCode());
// Kill the audio thread so we can take control.
captureThreadState = CT_WAITING;
OTRAudio_InstallSfxCaptureThread();
// Make sure we're starting from a clean slate.
std::string sohAccessibilityPath = Ship::Context::GetPathRelativeToAppDirectory("accessibility.otr");
std::string sohAccessibilityPath = Ship::Context::GetPathRelativeToAppDirectory("accessibility.o2r");
if (std::filesystem::exists(sohAccessibilityPath)) {
currentStep = STEP_ERROR_OTR;
return;
@ -115,10 +115,11 @@ void SfxExtractor::setup() {
for (int i = 1; i < 10; i++) {
progressMilestones[i - 1] = sfxToRip.size() - ((int)ceil(sfxToRip.size() * (i / 10.0f)));
}
archive = Ship::Context::GetInstance()->GetResourceManager()->GetArchiveManager()->AddArchive("accessibility.otr");
archive = std::make_shared<Ship::O2rArchive>("accessibility.o2r");
archive->Open();
} catch (...) { currentStep = STEP_ERROR; }
}
void SfxExtractor::ripNextSfx() {
{
auto lock = OTRAudio_Lock();
@ -143,7 +144,8 @@ void SfxExtractor::ripNextSfx() {
sfxToRip.pop();
startOfInput = 0;
endOfInput = 0;
Audio_PlaySoundGeneral(currentSfx, &gSfxDefaultPos, 4, &gSfxDefaultFreqAndVolScale, &gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb);
Audio_PlaySoundGeneral(currentSfx, &gSfxDefaultPos, 4, &gSfxDefaultFreqAndVolScale, &gSfxDefaultFreqAndVolScale,
&gSfxDefaultReverb);
{
auto lock = OTRAudio_Lock();
@ -161,17 +163,18 @@ void SfxExtractor::finished() {
Audio_QueueSeqCmd(NA_BGM_TITLE);
if (currentStep == STEP_ERROR || currentStep == STEP_ERROR_OTR) {
Audio_PlaySoundGeneral(NA_SE_SY_ERROR, &gSfxDefaultPos, 4, &gSfxDefaultFreqAndVolScale, &gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb);
Audio_PlaySoundGeneral(NA_SE_EN_GANON_LAUGH, &gSfxDefaultPos, 4, &gSfxDefaultFreqAndVolScale, &gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb);
Audio_PlaySoundGeneral(NA_SE_SY_ERROR, &gSfxDefaultPos, 4, &gSfxDefaultFreqAndVolScale,
&gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb);
Audio_PlaySoundGeneral(NA_SE_EN_GANON_LAUGH, &gSfxDefaultPos, 4, &gSfxDefaultFreqAndVolScale,
&gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb);
std::stringstream ss;
ss << "Sorry, we tried to extract the sound effects, but Ganondorf overruled us with an iron fist."
<< std::endl;
if (currentStep == STEP_ERROR_OTR)
ss << "In all seriousness, please delete accessibility.otr and try again.";
ss << "In all seriousness, please delete accessibility.o2r and try again.";
SpeechSynthesizer::Instance->Speak(ss.str().c_str(), GetLanguageCode());
} else
Audio_PlayFanfare(NA_BGM_ITEM_GET);
}
void SfxExtractor::maybeGiveProgressReport() {
size_t ripsRemaining = sfxToRip.size() + 1;
@ -188,7 +191,7 @@ SfxExtractor::SfxExtractor() {
currentStep = STEP_SETUP;
}
void SfxExtractor::frameCallback() {
void SfxExtractor::frameCallback() {
switch (currentStep) {
case STEP_SETUP:
setup();
@ -223,9 +226,9 @@ void SfxExtractor::captureCallback() {
AudioMgr_CreateNextAudioBuffer(mark, SFX_EXTRACTION_ONE_FRAME);
if (!outputStarted && isAllZero(mark, SFX_EXTRACTION_ONE_FRAME * 2)) {
waitTime++;
waitTime++;
if (waitTime < 300)
continue;//Output is silent, allow more time for audio to begin.
continue; // Output is silent, allow more time for audio to begin.
captureThreadState = CT_FINISHED; // Sound is unavailable, so skip over it and move on.
return;
}

View file

@ -1,6 +1,7 @@
#pragma once
//A big nasty array containing every SFX ID in the game.
//All of the "DUMMY's" and "YOBI's" have been removed as they produce duplicate sounds at best, and cause errors or even crashes at worst.
// A big nasty array containing every SFX ID in the game.
// All of the "DUMMY's" and "YOBI's" have been removed as they produce duplicate sounds at best, and cause errors or
// even crashes at worst.
const s16 sfxTable[1207] = {
NA_SE_PL_WALK_GROUND,

File diff suppressed because it is too large Load diff

View file

@ -274,7 +274,7 @@ OTRGlobals::OTRGlobals() {
if (std::filesystem::exists(ootPath)) {
OTRFiles.push_back(ootPath);
}
std::string sohOtrPath = Ship::Context::GetPathRelativeToAppBundle("soh.otr");
std::string sohOtrPath = Ship::Context::GetPathRelativeToAppBundle("soh.o2r");
if (std::filesystem::exists(sohOtrPath)) {
OTRFiles.push_back(sohOtrPath);
}