BST SE/STREAM replacement support

No SEQ yet since idk how I wanna handle it.
This commit is contained in:
PJB3005
2026-08-24 21:04:16 +02:00
parent 2fca463139
commit 2bc53dddcc
37 changed files with 832 additions and 128 deletions
+3 -2
View File
@@ -521,14 +521,15 @@ void Z2Audience::setAudioCamera(f32 (*viewMatrix)[4], Vec& pos, Vec& param_2, f3
}
JAIAudible* Z2Audience::newAudible(const JGeometry::TVec3<f32>& pos, JAISoundID soundID,
const JGeometry::TVec3<f32>* param_2, u32 param_3) {
const JGeometry::TVec3<f32>* param_2, u32 param_3
IF_DUSK_ARG(dusk::mods::svc::audio_res::bst::SoundTableReplacementSlot const* replacement)) {
u32 channelNum = param_3 | ~((1 << mNumPlayers) + -1);
if (channelNum == 0xFFFFFFFF) {
JUT_WARN(826, "%s", "You masked all audible channels !");
return NULL;
}
JAUAudibleParam params = Z2GetSoundInfo()->getAudibleSwFull(soundID);
JAUAudibleParam params = Z2GetSoundInfo()->getAudibleSwFull(soundID IF_DUSK_ARG(replacement));
bool x = params.field_0x0.bytes.mDopplerPower != 0;
Z2Audible* audible = JKR_NEW Z2Audible(pos, param_2, channelNum, x);
+1 -1
View File
@@ -1642,7 +1642,7 @@ void Z2SceneMgr::setSceneName(char* spot, s32 room, s32 layer) {
JSUList<JAIStream>* stream_list = Z2GetSoundMgr()->getStreamMgr()->getStreamList();
JSULink<JAIStream>* stream;
for (stream = stream_list->getFirst(); stream != NULL; stream = stream->getNext()) {
if (bVar2 || sound_table->getTypeID(stream->getObject()->getID()) != SOUND_TYPEID_STREAM) {
if (bVar2 || sound_table->getTypeID(stream->getObject()->getID() IF_DUSK_ARG(stream->getObject()->getReplacement())) != SOUND_TYPEID_STREAM) {
stream->getObject()->stop(Z2Param::SCENE_CHANGE_BGM_FADEOUT_TIME);
}
}
+2 -2
View File
@@ -89,7 +89,7 @@ Z2SoundHandlePool* Z2SoundHandles::getLowPrioSound(JAISoundID soundID) {
return handle;
}
u32 prio = soundInfo->getPriority((*handle)->getID());
u32 prio = soundInfo->getPriority((*handle)->getID() IF_DUSK_ARG((*handle)->getReplacement()));
if (prio < low_prio) {
low_prio = prio;
rethandle = handle;
@@ -102,7 +102,7 @@ Z2SoundHandlePool* Z2SoundHandles::getLowPrioSound(JAISoundID soundID) {
}
#endif
if (soundInfo->getPriority(soundID) >= low_prio) {
if (soundInfo->getPriority(soundID IF_DUSK_ARG(nullptr)) >= low_prio) {
return rethandle;
}
+88 -56
View File
@@ -1,11 +1,13 @@
#include "Z2AudioLib/Z2SoundInfo.h"
#include "JSystem/JAudio2/JAISeq.h"
#include "JSystem/JAudio2/JAISe.h"
#include "JSystem/JAudio2/JAISeq.h"
#include "JSystem/JAudio2/JAISoundChild.h"
#include "JSystem/JAudio2/JAIStream.h"
#include "JSystem/JAudio2/JAUSoundTable.h"
#include "JSystem/JUtility/JUTAssert.h"
#include "Z2AudioLib/Z2Calc.h"
#include "dusk/mods/svc/audio_res/bst.hpp"
struct JAUStdSoundTableType {
static DUSK_GAME_DATA const u32 STRM_CH_SHIFT;
@@ -18,8 +20,8 @@ struct JAUStdSoundTableType {
u16 Z2SoundInfo::getBgmSeqResourceID(JAISoundID soundID) const {
JUT_ASSERT(20, isValid());
JAUSoundTableItem* data = JASGlobalInstance<JAUSoundTable>::getInstance()->getData(soundID);
u8 typeID = JASGlobalInstance<JAUSoundTable>::getInstance()->getTypeID(soundID);
JAUSoundTableItem DUSK_CONST* data = JASGlobalInstance<JAUSoundTable>::getInstance()->getData(soundID IF_DUSK_ARG(nullptr));
u8 typeID = JASGlobalInstance<JAUSoundTable>::getInstance()->getTypeID(soundID IF_DUSK_ARG(nullptr));
if (data != NULL) {
switch ((typeID & 0xf0)) {
@@ -48,10 +50,22 @@ int Z2SoundInfo::getCategory(JAISoundID soundID) const {
return soundID.id_.info.type.parts.groupID;
}
u32 Z2SoundInfo::getPriority(JAISoundID soundID) const {
u32 Z2SoundInfo::getPriority(JAISoundID soundID IF_DUSK_ARG(SoundTableReplacementSlot const* replacement)) const {
JUT_ASSERT(63, isValid());
JAUSoundTableItem* data = JASGlobalInstance<JAUSoundTable>::getInstance()->getData(soundID);
u8 typeID = JASGlobalInstance<JAUSoundTable>::getInstance()->getTypeID(soundID);
#if TARGET_PC
// This function gets called at least once in a context where we can't easily pass in the replacement.
// So check it here too.
// It's only a tiny priority difference, highly unlikely to cause any issues.
std::shared_ptr<SoundTableReplacementSlot> replacement_shared;
if (!replacement) {
replacement_shared = dusk::mods::svc::audio_res::bst::get_override_for(soundID);
replacement = replacement_shared.get();
}
#endif
JAUSoundTableItem DUSK_CONST* data = JASGlobalInstance<JAUSoundTable>::getInstance()->getData(soundID IF_DUSK_ARG(replacement));
u8 typeID = JASGlobalInstance<JAUSoundTable>::getInstance()->getTypeID(soundID IF_DUSK_ARG(replacement));
if (data != NULL && (typeID & SOUND_TYPEID_VALID) != 0) {
return data->mPriority;
@@ -60,59 +74,65 @@ u32 Z2SoundInfo::getPriority(JAISoundID soundID) const {
return 0;
}
JAUAudibleParam Z2SoundInfo::getAudibleSwFull(JAISoundID soundID) {
#define SW_BIT DUSK_IF_ELSE(sw_bit, getSwBit(soundID))
JAUAudibleParam Z2SoundInfo::getAudibleSwFull(JAISoundID soundID IF_DUSK_ARG(SoundTableReplacementSlot const* replacement)) {
JAUAudibleParam audibleParam;
JUT_ASSERT(82, isValid());
int iVar1, uVar7;
u8 typeID = JASGlobalInstance<JAUSoundTable>::getInstance()->getTypeID(soundID);
IF_DUSK(int sw_bit;)
u8 typeID = JASGlobalInstance<JAUSoundTable>::getInstance()->getTypeID(soundID IF_DUSK_ARG(replacement));
switch (typeID) {
case SOUND_TYPEID_SOUND_EFFECT:
audibleParam.field_0x0.bytes.mDopplerPower = (u32)getSwBit(soundID) >> SOUND_SW_DOPPLER_POWER_OFFSET;
if ((getSwBit(soundID) & SOUND_SW_ALWAYS_MAX_PRIORITY) != 0) {
IF_DUSK(sw_bit = getSwBit(soundID, replacement);)
audibleParam.field_0x0.bytes.mDopplerPower = (u32)SW_BIT >> SOUND_SW_DOPPLER_POWER_OFFSET;
if ((SW_BIT & SOUND_SW_ALWAYS_MAX_PRIORITY) != 0) {
audibleParam.field_0x0.bytes.mCalculatePriority = 0;
} else {
audibleParam.field_0x0.bytes.mCalculatePriority = 1;
}
if ((getSwBit(soundID) & SOUND_SW_IGNORE_DISTANCE_VOL) != 0) {
if ((SW_BIT & SOUND_SW_IGNORE_DISTANCE_VOL) != 0) {
audibleParam.field_0x0.bytes.mCalcDistanceVolume = 0;
} else {
audibleParam.field_0x0.bytes.mCalcDistanceVolume = 1;
}
if ((getSwBit(soundID) & SOUND_SW_IGNORE_FX_MIX) != 0) {
if ((SW_BIT & SOUND_SW_IGNORE_FX_MIX) != 0) {
audibleParam.field_0x0.bytes.mCalcFxMix = 0;
} else {
audibleParam.field_0x0.bytes.mCalcFxMix = 1;
}
if ((getSwBit(soundID) & SOUND_SW_CULL_AT_MAX_DISTANCE) != 0) {
if ((SW_BIT & SOUND_SW_CULL_AT_MAX_DISTANCE) != 0) {
audibleParam.field_0x0.bytes.mCullAtMaxDistance = 1;
} else {
audibleParam.field_0x0.bytes.mCullAtMaxDistance = 0;
}
if ((getSwBit(soundID) & SOUND_SW_IGNORE_PAN) != 0) {
if ((SW_BIT & SOUND_SW_IGNORE_PAN) != 0) {
audibleParam.field_0x0.bytes.mCalcPan = 0;
} else {
audibleParam.field_0x0.bytes.mCalcPan = 1;
}
if ((getSwBit(soundID) & SOUND_SW_IGNORE_DOLBY) != 0) {
if ((SW_BIT & SOUND_SW_IGNORE_DOLBY) != 0) {
audibleParam.field_0x0.bytes.mCalcDolby = 0;
} else {
audibleParam.field_0x0.bytes.mCalcDolby = 1;
}
uVar7 = 0;
if ((getSwBit(soundID) & SOUND_SW_CLAMP_MIN_VOLUME) != 0) {
if ((SW_BIT & SOUND_SW_CLAMP_MIN_VOLUME) != 0) {
uVar7 = 8;
}
iVar1 = (getSwBit(soundID) >> 16) & SOUND_VOL_DIST_BIT_MASK_SHIFTED;
iVar1 += (getSwBit(soundID) >> 16) & SOUND_VOL_DIST_BIT_2_MASK_SHIFTED;
iVar1 += (getSwBit(soundID) >> 16) & SOUND_VOL_SOMETHING_MASK_SHIFTED;
iVar1 = (SW_BIT >> 16) & SOUND_VOL_DIST_BIT_MASK_SHIFTED;
iVar1 += (SW_BIT >> 16) & SOUND_VOL_DIST_BIT_2_MASK_SHIFTED;
iVar1 += (SW_BIT >> 16) & SOUND_VOL_SOMETHING_MASK_SHIFTED;
audibleParam.field_0x0.bytes.mClampMinVolume = uVar7;
audibleParam.field_0x0.half.f1 = iVar1;
break;
@@ -132,59 +152,63 @@ JAUAudibleParam Z2SoundInfo::getAudibleSwFull(JAISoundID soundID) {
return audibleParam;
}
u16 Z2SoundInfo::getAudibleSw(JAISoundID soundID) const {
u16 Z2SoundInfo::getAudibleSw(JAISoundID soundID IF_DUSK_ARG(SoundTableReplacementSlot const* replacement)) const {
JAUAudibleParam audibleParam;
JUT_ASSERT(184, isValid());
int iVar1, uVar7;
u8 typeID = JASGlobalInstance<JAUSoundTable>::getInstance()->getTypeID(soundID);
IF_DUSK(int sw_bit);
u8 typeID = JASGlobalInstance<JAUSoundTable>::getInstance()->getTypeID(soundID IF_DUSK_ARG(replacement));
switch (typeID) {
case SOUND_TYPEID_SOUND_EFFECT:
audibleParam.field_0x0.bytes.mDopplerPower = (u32)getSwBit(soundID) >> SOUND_SW_DOPPLER_POWER_OFFSET;
if ((getSwBit(soundID) & SOUND_SW_ALWAYS_MAX_PRIORITY) != 0) {
IF_DUSK(sw_bit = getSwBit(soundID, replacement);)
audibleParam.field_0x0.bytes.mDopplerPower = (u32)SW_BIT >> SOUND_SW_DOPPLER_POWER_OFFSET;
if ((SW_BIT & SOUND_SW_ALWAYS_MAX_PRIORITY) != 0) {
audibleParam.field_0x0.bytes.mCalculatePriority = 0;
} else {
audibleParam.field_0x0.bytes.mCalculatePriority = 1;
}
if ((getSwBit(soundID) & SOUND_SW_IGNORE_DISTANCE_VOL) != 0) {
if ((SW_BIT & SOUND_SW_IGNORE_DISTANCE_VOL) != 0) {
audibleParam.field_0x0.bytes.mCalcDistanceVolume = 0;
} else {
audibleParam.field_0x0.bytes.mCalcDistanceVolume = 1;
}
if ((getSwBit(soundID) & 4) != 0) {
if ((SW_BIT & SOUND_SW_IGNORE_FX_MIX) != 0) {
audibleParam.field_0x0.bytes.mCalcFxMix = 0;
} else {
audibleParam.field_0x0.bytes.mCalcFxMix = 1;
}
if ((getSwBit(soundID) & SOUND_SW_CULL_AT_MAX_DISTANCE) != 0) {
if ((SW_BIT & SOUND_SW_CULL_AT_MAX_DISTANCE) != 0) {
audibleParam.field_0x0.bytes.mCullAtMaxDistance = 1;
} else {
audibleParam.field_0x0.bytes.mCullAtMaxDistance = 0;
}
if ((getSwBit(soundID) & SOUND_SW_IGNORE_PAN) != 0) {
if ((SW_BIT & SOUND_SW_IGNORE_PAN) != 0) {
audibleParam.field_0x0.bytes.mCalcPan = 0;
} else {
audibleParam.field_0x0.bytes.mCalcPan = 1;
}
if ((getSwBit(soundID) & SOUND_SW_IGNORE_DOLBY) != 0) {
if ((SW_BIT & SOUND_SW_IGNORE_DOLBY) != 0) {
audibleParam.field_0x0.bytes.mCalcDolby = 0;
} else {
audibleParam.field_0x0.bytes.mCalcDolby = 1;
}
uVar7 = 0;
if ((getSwBit(soundID) & SOUND_SW_CLAMP_MIN_VOLUME) != 0) {
if ((SW_BIT & SOUND_SW_CLAMP_MIN_VOLUME) != 0) {
uVar7 = 8;
}
iVar1 = (getSwBit(soundID) >> 16) & SOUND_VOL_DIST_BIT_MASK_SHIFTED;
iVar1 += (getSwBit(soundID) >> 16) & SOUND_VOL_DIST_BIT_2_MASK_SHIFTED;
iVar1 += (getSwBit(soundID) >> 16) & SOUND_VOL_SOMETHING_MASK_SHIFTED;
iVar1 = (SW_BIT >> 16) & SOUND_VOL_DIST_BIT_MASK_SHIFTED;
iVar1 += (SW_BIT >> 16) & SOUND_VOL_DIST_BIT_2_MASK_SHIFTED;
iVar1 += (SW_BIT >> 16) & SOUND_VOL_SOMETHING_MASK_SHIFTED;
audibleParam.field_0x0.bytes.mClampMinVolume = uVar7;
audibleParam.field_0x0.half.f1 = iVar1;
break;
@@ -197,12 +221,14 @@ u16 Z2SoundInfo::getAudibleSw(JAISoundID soundID) const {
return audibleParam.field_0x0.half.f0;
}
void Z2SoundInfo::getSeInfo(JAISoundID soundID, JAISe* sePtr) const {
#undef SW_BIT
void Z2SoundInfo::getSeInfo(JAISoundID soundID, JAISe* sePtr IF_DUSK_ARG(SoundEffectReplacementSlot const* replacement)) const {
getSoundInfo_(soundID, sePtr);
JUT_ASSERT(292, isValid());
JAUSoundTableItem* data = JASGlobalInstance<JAUSoundTable>::getInstance()->getData(soundID);
u8 typeID = JASGlobalInstance<JAUSoundTable>::getInstance()->getTypeID(soundID);
JAUSoundTableItem DUSK_CONST* data = JASGlobalInstance<JAUSoundTable>::getInstance()->getData(soundID IF_DUSK_ARG(replacement));
u8 typeID = JASGlobalInstance<JAUSoundTable>::getInstance()->getTypeID(soundID IF_DUSK_ARG(replacement));
if (data == NULL) {
return;
}
@@ -210,14 +236,14 @@ void Z2SoundInfo::getSeInfo(JAISoundID soundID, JAISe* sePtr) const {
switch(typeID) {
case SOUND_TYPEID_SOUND_EFFECT:
sePtr->getProperty().mPitch *= data->mPitch;
u32 pitchParam = (getSwBit(soundID) & SOUND_SW_RANDOM_PITCH_MASK) >> SOUND_SW_RANDOM_PITCH_OFFSET;
u32 pitchParam = (getSwBit(soundID IF_DUSK_ARG(replacement)) & SOUND_SW_RANDOM_PITCH_MASK) >> SOUND_SW_RANDOM_PITCH_OFFSET;
if (pitchParam > 8) {
sePtr->getProperty().mPitch += Z2Calc::linearTransform(pitchParam, 8.0f, 15.0f, 16.0f, 24.0f, true) / 48.0f * Z2Calc::getRandom_0_1();
} else {
sePtr->getProperty().mPitch += (pitchParam / 48.0f) * Z2Calc::getRandom_0_1();
}
u32 uVar1 = (u32)getSwBit(soundID) >> SOUND_SW_RANDOM_VOLUME_OFFSET;
u32 uVar1 = (u32)getSwBit(soundID IF_DUSK_ARG(replacement)) >> SOUND_SW_RANDOM_VOLUME_OFFSET;
if (uVar1 != 0) {
f32 dVar18 = (uVar1 / 15.0f) * Z2Calc::getRandom_0_1();
sePtr->getProperty().mVolume -= dVar18 < 0.0f ? 0.0f : (dVar18 > 1.0f ? 1.0f : dVar18);
@@ -230,20 +256,20 @@ void Z2SoundInfo::getSeqInfo(JAISoundID soundID, JAISeq* seqPtr) const {
getSoundInfo_(soundID, seqPtr);
}
DUSK_GAME_DATA const u32 JAUStdSoundTableType::STRM_CH_SHIFT = 2;
DUSK_GAME_DATA const u32 JAUStdSoundTableType::STRM_CH_SHIFT = STRM_CH_SHIFT_;
void Z2SoundInfo::getStreamInfo(JAISoundID soundID, JAIStream* streamPtr) const {
void Z2SoundInfo::getStreamInfo(JAISoundID soundID, JAIStream* streamPtr IF_DUSK_ARG(StreamReplacementSlot const* replacement)) const {
int numChild;
JAUSoundTableItem* data;
JAUSoundTableItem DUSK_CONST* data;
getSoundInfo_(soundID, streamPtr);
JUT_ASSERT(349, isValid());
u8 typeID = JASGlobalInstance<JAUSoundTable>::getInstance()->getTypeID(soundID);
u8 typeID = JASGlobalInstance<JAUSoundTable>::getInstance()->getTypeID(soundID IF_DUSK_ARG(replacement));
switch (typeID & 0xf0) {
case SOUND_TYPEID_STREAM:
u16 uVar1;
s32 iVar4;
data = JASGlobalInstance<JAUSoundTable>::getInstance()->getData(soundID);
data = JASGlobalInstance<JAUSoundTable>::getInstance()->getData(soundID IF_DUSK_ARG(replacement));
JUT_ASSERT(356, data);
uVar1 = data->mStreamPanParameters;
@@ -255,13 +281,13 @@ void Z2SoundInfo::getStreamInfo(JAISoundID soundID, JAIStream* streamPtr) const
JAISoundChild* child = streamPtr->getChild(iVar4);
if (child != NULL) {
switch (uVar2) {
case 1:
case STRM_CH_CENTER:
child->mMove.params_.mPan = 0.5f;
break;
case 2:
case STRM_CH_LEFT:
child->mMove.params_.mPan = 0.0f;
break;
case 3:
case STRM_CH_RIGHT:
child->mMove.params_.mPan = 1.0f;
break;
}
@@ -271,14 +297,20 @@ void Z2SoundInfo::getStreamInfo(JAISoundID soundID, JAIStream* streamPtr) const
}
}
const char* Z2SoundInfo::getStreamFilePath(JAISoundID soundID) {
const char* Z2SoundInfo::getStreamFilePath(JAISoundID soundID IF_DUSK_ARG(StreamReplacementSlot const* replacement)) {
JUT_ASSERT(387, isValid());
JAUSoundTableItem* data;
JAUSoundTableItem DUSK_CONST* data;
const void* resource;
switch (JASGlobalInstance<JAUSoundTable>::getInstance()->getTypeID(soundID) & 0xf0) {
switch (JASGlobalInstance<JAUSoundTable>::getInstance()->getTypeID(soundID IF_DUSK_ARG(replacement)) & 0xf0) {
case SOUND_TYPEID_STREAM:
data = JASGlobalInstance<JAUSoundTable>::getInstance()->getData(soundID);
#if TARGET_PC
if (replacement) {
return replacement->file_path.c_str();
}
#endif
data = JASGlobalInstance<JAUSoundTable>::getInstance()->getData(soundID IF_DUSK_ARG(replacement));
JUT_ASSERT(394, data);
resource = JASGlobalInstance<JAUSoundTable>::getInstance()->getResource();
JUT_ASSERT(398, resource);
@@ -288,16 +320,16 @@ const char* Z2SoundInfo::getStreamFilePath(JAISoundID soundID) {
}
}
s32 Z2SoundInfo::getStreamFileEntry(JAISoundID soundID) {
const char* path = getStreamFilePath(soundID);
s32 Z2SoundInfo::getStreamFileEntry(JAISoundID soundID IF_DUSK_ARG(StreamReplacementSlot const* replacement)) {
const char* path = getStreamFilePath(soundID IF_DUSK_ARG(replacement));
return !path ? -1 : DVDConvertPathToEntrynum(path);
}
int Z2SoundInfo::getSwBit(JAISoundID soundID) const {
int Z2SoundInfo::getSwBit(JAISoundID soundID IF_DUSK_ARG(SoundTableReplacementSlot const* replacement)) const {
JUT_ASSERT(418, isValid());
JAUSoundTableItem* data = JASGlobalInstance<JAUSoundTable>::getInstance()->getData(soundID);
JAUSoundTableItem DUSK_CONST* data = JASGlobalInstance<JAUSoundTable>::getInstance()->getData(soundID IF_DUSK_ARG(replacement));
u8 typeID = JASGlobalInstance<JAUSoundTable>::getInstance()->getTypeID(soundID);
u8 typeID = JASGlobalInstance<JAUSoundTable>::getInstance()->getTypeID(soundID IF_DUSK_ARG(replacement));
if (data != NULL) {
switch(typeID) {
case SOUND_TYPEID_SOUND_EFFECT:
@@ -310,9 +342,9 @@ int Z2SoundInfo::getSwBit(JAISoundID soundID) const {
void Z2SoundInfo::getSoundInfo_(JAISoundID soundID, JAISound* soundPtr) const {
JUT_ASSERT(440, isValid());
JAUSoundTableItem* data = JASGlobalInstance<JAUSoundTable>::getInstance()->getData(soundID);
JAUSoundTableItem DUSK_CONST* data = JASGlobalInstance<JAUSoundTable>::getInstance()->getData(soundID IF_DUSK_ARG(soundPtr->getReplacement()));
u8 typeID = JASGlobalInstance<JAUSoundTable>::getInstance()->getTypeID(soundID);
u8 typeID = JASGlobalInstance<JAUSoundTable>::getInstance()->getTypeID(soundID IF_DUSK_ARG(soundPtr->getReplacement()));
if (data != NULL && (typeID & SOUND_TYPEID_VALID) != 0) {
soundPtr->getProperty().mVolume = (1.0f / 127.0f) * data->mVolume;
}
+29 -15
View File
@@ -1,14 +1,15 @@
#include "Z2AudioLib/Z2SoundMgr.h"
#include "Z2AudioLib/Z2Param.h"
#include "Z2AudioLib/Z2SceneMgr.h"
#include "Z2AudioLib/Z2SpeechMgr2.h"
#include "Z2AudioLib/Z2SeqMgr.h"
#include "Z2AudioLib/Z2SeMgr.h"
#include "Z2AudioLib/Z2SoundInfo.h"
#include "JSystem/JAudio2/JASCalc.h"
#include "JSystem/JAudio2/JASDriverIF.h"
#include "JSystem/JAudio2/JAUSectionHeap.h"
#include "Z2AudioLib/Z2Param.h"
#include "Z2AudioLib/Z2SceneMgr.h"
#include "Z2AudioLib/Z2SeMgr.h"
#include "Z2AudioLib/Z2SeqMgr.h"
#include "Z2AudioLib/Z2SoundInfo.h"
#include "Z2AudioLib/Z2SpeechMgr2.h"
#include "d/d_com_inf_game.h"
#include "dusk/mods/svc/audio_res/bst.hpp"
#if PLATFORM_WII || PLATFORM_SHIELD
#include "Z2AudioCS/Z2AudioCS.h"
@@ -113,19 +114,25 @@ Z2SoundMgr::Z2SoundMgr() :
seqMgr_(true),
streamMgr_(true)
{
soundID_.setAnonymous();
bgmMuter.setAnonymous();
}
bool Z2SoundMgr::startSound(JAISoundID soundID, JAISoundHandle* handle, const JGeometry::TVec3<f32>* posPtr) {
DUSK_AUDIO_SKIP(true);
IF_DUSK(using namespace dusk::mods::svc::audio_res::bst);
int soundType = Z2GetSoundInfo()->getSoundType(soundID);
switch (soundType) {
case 0: {
if (Z2GetSoundInfo()->getSwBit(soundID) & 8) {
#if TARGET_PC
{
auto replace_se = get_override_for_se(soundID);
#endif
if (Z2GetSoundInfo()->getSwBit(soundID IF_DUSK_ARG(replace_se.get())) & SOUND_SW_MUTE_BGM) {
OS_REPORT("[Z2SoundMgr::startSound] se seq Mute! id = %08x\n", *(u32*)&soundID);
Z2GetSeqMgr()->bgmAllMute(3, 0.3f);
soundID_ = soundID;
bgmMuter = soundID;
}
#if PLATFORM_WII || PLATFORM_SHIELD
@@ -136,15 +143,16 @@ bool Z2SoundMgr::startSound(JAISoundID soundID, JAISoundHandle* handle, const JG
}
#endif
bool result = seMgr_.startSound(soundID, handle, posPtr);
bool result = seMgr_.startSound(soundID, handle, posPtr IF_DUSK_ARG(std::move(replace_se)));
return result;
IF_DUSK_BLOCK_END
}
case 1:
if (soundID == Z2BGM_LUTERA_DEMO) {
Z2GetSeqMgr()->bgmStart(Z2BGM_LUTERA2, 0, 0);
Z2GetSeqMgr()->unMuteSceneBgm(0);
Z2GetSeqMgr()->changeBgmStatus(0);
return seMgr_.startSound(Z2SE_NO_SOUND, handle, posPtr);
return seMgr_.startSound(Z2SE_NO_SOUND, handle, posPtr IF_DUSK_ARG(nullptr));
} else {
bool loaded = false;
JAUSectionHeap* sectionHeap = JASGlobalInstance<JAUSectionHeap>::getInstance();
@@ -172,15 +180,21 @@ bool Z2SoundMgr::startSound(JAISoundID soundID, JAISoundHandle* handle, const JG
return seqMgr_.startSound(soundID, handle, posPtr);
}
case 2:
#if TARGET_PC
{
auto replace_stream = get_override_for_stream(soundID);
#endif
if (soundID == 0x2000001 || soundID == 0x200004d) {
streamMgr_.stop(180);
return seMgr_.startSound(Z2SE_NO_SOUND, handle, posPtr);
return seMgr_.startSound(Z2SE_NO_SOUND, handle, posPtr IF_DUSK_ARG(nullptr));
}
if (soundID == 0x2000005) {
seMgr_.getCategory(9)->pause(false);
seMgr_.getCategory(9)->getParams()->moveVolume(1.0f, 45);
}
return streamMgr_.startSound(soundID, handle, posPtr);
return streamMgr_.startSound(soundID, handle, posPtr IF_DUSK_ARG(std::move(replace_stream)));
IF_DUSK_BLOCK_END
default:
char error[64];
SAFE_SPRINTF(error, "Unknown Sound-Type id :%08x\n", (u32)soundID);
@@ -192,11 +206,11 @@ bool Z2SoundMgr::startSound(JAISoundID soundID, JAISoundHandle* handle, const JG
void Z2SoundMgr::calc() {
seMgr_.calc();
if (!soundID_.isAnonymous() && !isPlayingSoundID(soundID_)) {
if (!bgmMuter.isAnonymous() && !isPlayingSoundID(bgmMuter)) {
if (Z2GetSceneMgr()->isSceneExist()) {
Z2GetSeqMgr()->bgmAllUnMute(3);
}
soundID_.setAnonymous();
bgmMuter.setAnonymous();
}
seqMgr_.calc();
streamMgr_.calc();
+3 -3
View File
@@ -70,7 +70,7 @@ void Z2SoundObjBase::dispose() {
for (i = getFirst(); i != NULL; i = i->getNext()) {
handle = i->getObject();
if (handle != NULL && *handle) {
if ((Z2GetSoundInfo()->getSwBit((*handle)->getID()) & 0x8000) != 0) {
if ((Z2GetSoundInfo()->getSwBit((*handle)->getID() IF_DUSK_ARG((*handle)->getReplacement())) & SOUND_SW_POOL_FLAG_2) != 0) {
handle->releaseSound();
} else {
(*handle)->stop();
@@ -82,7 +82,7 @@ void Z2SoundObjBase::dispose() {
}
bool Z2SoundObjBase::stopOK(Z2SoundHandlePool& handlePool) {
if ((Z2GetSoundInfo()->getSwBit(handlePool->getID()) & 0x8000) != 0) {
if ((Z2GetSoundInfo()->getSwBit(handlePool->getID() IF_DUSK_ARG(handlePool->getReplacement())) & SOUND_SW_POOL_FLAG_2) != 0) {
return false;
} else {
return true;
@@ -112,7 +112,7 @@ Z2SoundHandlePool* Z2SoundObjBase::startSound(JAISoundID soundID, u32 mapinfo, s
Z2SoundHandlePool* handle = getHandleSoundID(soundID);
if (handle != NULL) {
if ((Z2GetSoundInfo()->getSwBit(soundID) & 0x4000) != 0) {
if ((Z2GetSoundInfo()->getSwBit(soundID IF_DUSK_ARG((*handle)->getReplacement())) & SOUND_SW_POOL_FLAG_1) != 0) {
handle = NULL;
} else {
return NULL;
@@ -5,6 +5,7 @@
#include "../registry.hpp"
#include "wsys.hpp"
#include "bst.hpp"
namespace dusk::mods::svc {
@@ -18,18 +19,26 @@ constexpr AudioResService s_audioResService{
.replace_wave = &wsys::insert_replace_wave,
.add_wave = &wsys::insert_add_wave,
.remove_wave = &wsys::remove_wave,
.replace_sound_table_effect = &bst::replace_sound_table_effect,
.add_sound_table_effect = &bst::add_sound_table_effect,
.replace_sound_table_stream = &bst::replace_sound_table_stream,
.add_sound_table_stream = &bst::add_sound_table_stream,
.remove_sound_table = &bst::remove_sound_table,
};
void frame_end() {
wsys::frame_end();
bst::frame_end();
}
void mod_detached(LoadedMod& mod) {
wsys::remove_mod(mod);
bst::remove_mod(mod);
}
void sync_audio_replacements() {
wsys::sync_audio_replacements();
bst::sync_audio_replacements();
}
}
+350
View File
@@ -0,0 +1,350 @@
#include "bst.hpp"
#include "aurora/lib/logging.hpp"
#include "dusk/mods/loader/loader.hpp"
#include "dusk/mods/svc/id_allocator.hpp"
#include "dusk/mods/svc/slot_map.hpp"
namespace dusk::mods::svc::audio_res::bst {
namespace {
bool sound_replacements_dirty = false;
aurora::Module Log("dusk::mods::svc::audio_res");
SlotMap<std::shared_ptr<SoundTableReplacementSlot>> sound_replacements;
std::array sound_effect_id_allocator = {
PlainIdAllocator<u16>(0x1000), // SYSTEM_SE
PlainIdAllocator<u16>(0x1000), // PLAYER_VOICE
PlainIdAllocator<u16>(0x1000), // PLAYER_SE
PlainIdAllocator<u16>(0x1000), // FOOTNOTE_SE
PlainIdAllocator<u16>(0x1000), // COLLISION_SE
PlainIdAllocator<u16>(0x1000), // CHARA_VOICE
PlainIdAllocator<u16>(0x1000), // CHARA_SE
PlainIdAllocator<u16>(0x1000), // ENEMY_SE
PlainIdAllocator<u16>(0x1000), // OBJECT_SE
PlainIdAllocator<u16>(0x1000), // ENV_SE
};
PlainIdAllocator<u16> stream_id_allocator(0x1000);
bool validate_category(SoundEffectCategory const category) {
return category <= SE_CATEGORY_ENV_SE;
}
uint8_t volume_to_item(float volume) {
return static_cast<uint8_t>(volume * 127);
}
absl::flat_hash_map<SoundEffectKey, std::shared_ptr<SoundEffectReplacementSlot>> active_se_replacements;
absl::flat_hash_map<u16, std::shared_ptr<StreamReplacementSlot>> active_stream_replacements;
std::mutex active_replacements_mutex;
} // namespace
SoundTableReplacementSlot::SoundTableReplacementSlot(bool const mod_defined, u16 const id)
: mod_defined(mod_defined), id(id), item() {}
SoundTableReplacementSlot::~SoundTableReplacementSlot() = default;
SoundEffectReplacementSlot::SoundEffectReplacementSlot(
bool mod_defined, u16 id, SoundEffectCategory category, const AudioSoundTableEffectInfo& info)
: SoundTableReplacementSlot(mod_defined, id), category(category) {
item.mPriority = info.priority;
item.mVolume = volume_to_item(info.volume);
item.mPitch = info.pitch;
u32 sw_bit = 0;
if (info.always_max_priority)
sw_bit |= SOUND_SW_ALWAYS_MAX_PRIORITY;
if (info.ignore_distance_volume)
sw_bit |= SOUND_SW_IGNORE_DISTANCE_VOL;
if (info.ignore_distance_fx_mix)
sw_bit |= SOUND_SW_IGNORE_FX_MIX;
if (info.ignore_pan)
sw_bit |= SOUND_SW_IGNORE_PAN;
if (info.ignore_dolby)
sw_bit |= SOUND_SW_IGNORE_DOLBY;
sw_bit |= (info.random_volume << SOUND_SW_RANDOM_VOLUME_OFFSET) & SOUND_SW_RANDOM_VOLUME_MASK;
sw_bit |= (info.random_pitch << SOUND_SW_RANDOM_PITCH_OFFSET) & SOUND_SW_RANDOM_PITCH_MASK;
sw_bit |= (info.doppler_power << SOUND_SW_DOPPLER_POWER_OFFSET) & SOUND_SW_DOPPLER_POWER_MASK;
if (info.volume_dist_class < 8) {
sw_bit |= (info.volume_dist_class << SOUND_SW_VOL_DIST_BIT_OFFSET) & SOUND_SW_VOL_DIST_BIT_MASK;
} else {
sw_bit |= ((info.volume_dist_class - 8) << SOUND_SW_VOL_DIST_BIT_2_OFFSET) & SOUND_SW_VOL_DIST_BIT_2_MASK;
}
if (info.clamp_min_volume)
sw_bit |= SOUND_SW_CLAMP_MIN_VOLUME;
if (info.cull_at_max_distance)
sw_bit |= SOUND_SW_CULL_AT_MAX_DISTANCE;
item.mSwBit = sw_bit;
}
u8 SoundEffectReplacementSlot::get_type_id() const {
return SOUND_TYPEID_SOUND_EFFECT;
}
StreamReplacementSlot::StreamReplacementSlot(
bool mod_defined, u16 id, const AudioSoundTableStreamInfo& info)
: SoundTableReplacementSlot(mod_defined, id), file_path(info.file_path) {
stop_on_scene_change = info.stop_on_scene_change;
item.mPriority = info.priority;
item.mVolume = volume_to_item(info.volume);
u16 panParam = 0;
for (int i = STREAM_MAX_CHILDREN - 1; i >= 0; i--) {
panParam <<= STRM_CH_SHIFT_;
switch (info.pan_parameters[i]) {
case STREAM_PAN_CENTER:
panParam |= STRM_CH_CENTER;
break;
case STREAM_PAN_LEFT:
panParam |= STRM_CH_LEFT;
break;
case STREAM_PAN_RIGHT:
panParam |= STRM_CH_RIGHT;
break;
}
}
item.mStreamPanParameters = panParam;
}
u8 StreamReplacementSlot::get_type_id() const {
return stop_on_scene_change ? SOUND_TYPEID_STREAM_ALT : SOUND_TYPEID_STREAM;
}
std::shared_ptr<SoundTableReplacementSlot> get_override_for(JAISoundID id) {
switch (id.id_.info.type.parts.sectionID) {
case 0:
return get_override_for_se(id);
case 2:
return get_override_for_stream(id);
default:
return nullptr;
}
}
std::shared_ptr<SoundEffectReplacementSlot> get_override_for_se(JAISoundID id) {
if (id.id_.info.type.parts.sectionID != 0) {
return nullptr;
}
std::lock_guard lock(active_replacements_mutex);
SoundEffectKey const key(
static_cast<SoundEffectCategory>(id.id_.info.type.parts.groupID),
id.id_.info.waveID);
auto const entry = active_se_replacements.find(key);
if (entry == active_se_replacements.end()) {
return nullptr;
}
return entry->second;
}
std::shared_ptr<StreamReplacementSlot> get_override_for_stream(JAISoundID id) {
if (id.id_.info.type.parts.sectionID != 2) {
return nullptr;
}
std::lock_guard lock(active_replacements_mutex);
auto const entry = active_stream_replacements.find(id.id_.info.waveID);
if (entry == active_stream_replacements.end()) {
return nullptr;
}
return entry->second;
}
void remove_mod(LoadedMod const& mod) {
sound_replacements.erase_all(mod);
sound_replacements_dirty = true;
}
void frame_end() {
if (sound_replacements_dirty) {
sync_audio_replacements();
}
}
void sync_audio_replacements() {
sound_replacements_dirty = false;
absl::flat_hash_map<SoundEffectKey, std::shared_ptr<SoundEffectReplacementSlot>> new_se_replacements;
absl::flat_hash_map<u16, std::shared_ptr<StreamReplacementSlot>> new_stream_replacements;
for (auto const& mod : ModLoader::instance().active_mods()) {
sound_replacements.for_each([&](auto, auto const& entry) {
if (entry.owner != &mod) {
return;
}
std::shared_ptr<SoundTableReplacementSlot> const& value = entry.value;
auto se = std::dynamic_pointer_cast<SoundEffectReplacementSlot>(value);
if (se) {
new_se_replacements.emplace(SoundEffectKey(se->category, se->id), std::move(se));
return;
}
auto stream = std::dynamic_pointer_cast<StreamReplacementSlot>(value);
if (stream) {
new_stream_replacements.emplace(stream->id, std::move(stream));
return;
}
});
}
std::lock_guard lock(active_replacements_mutex);
std::exchange(active_se_replacements, std::move(new_se_replacements));
std::exchange(active_stream_replacements, std::move(new_stream_replacements));
}
static ModResult insert_sound_table_effect_core(ModContext* ctx, SoundEffectCategory category_id,
uint16_t effect_id, bool mod_defined, AudioSoundTableEffectInfo const* info, AudioSoundTableHandle* out_handle) {
if (out_handle != nullptr) {
*out_handle = 0;
}
auto mod = mod_from_context(ctx);
if (mod == nullptr || info == nullptr || !validate_category(category_id)) {
return MOD_INVALID_ARGUMENT;
}
auto slot = std::make_shared<SoundEffectReplacementSlot>(mod_defined, effect_id, category_id, *info);
sound_replacements_dirty = true;
auto const handle = sound_replacements.emplace(*mod, std::move(slot));
if (out_handle) {
*out_handle = handle;
}
return MOD_OK;
}
ModResult replace_sound_table_effect(ModContext* ctx, SoundEffectCategory category_id,
uint16_t effect_id, AudioSoundTableEffectInfo const* info, AudioSoundTableHandle* out_handle) {
return insert_sound_table_effect_core(ctx, category_id, effect_id, false, info, out_handle);
}
ModResult add_sound_table_effect(ModContext* ctx, SoundEffectCategory category_id,
AudioSoundTableEffectInfo const* info, AudioSoundTableHandle* out_handle,
uint16_t* out_effect_id) {
if (out_effect_id == nullptr || !validate_category(category_id)) {
return MOD_INVALID_ARGUMENT;
}
assert(category_id < sound_effect_id_allocator.size());
auto& allocator = sound_effect_id_allocator[category_id];
auto const effect_id = allocator.alloc();
auto const result = insert_sound_table_effect_core(ctx, category_id, effect_id, true, info, out_handle);
if (result != MOD_OK) {
allocator.free(effect_id);
}
*out_effect_id = effect_id;
return result;
}
static ModResult insert_sound_table_stream_core(
ModContext* ctx,
uint16_t stream_id,
bool mod_defined,
AudioSoundTableStreamInfo const* info,
AudioSoundTableHandle* out_handle) {
if (out_handle != nullptr) {
*out_handle = 0;
}
auto mod = mod_from_context(ctx);
if (mod == nullptr || info == nullptr) {
return MOD_INVALID_ARGUMENT;
}
auto slot = std::make_shared<StreamReplacementSlot>(mod_defined, stream_id, *info);
sound_replacements_dirty = true;
auto const handle = sound_replacements.emplace(*mod, std::move(slot));
if (out_handle) {
*out_handle = handle;
}
return MOD_OK;
}
ModResult replace_sound_table_stream(ModContext* ctx, uint16_t stream_id,
AudioSoundTableStreamInfo const* info, AudioSoundTableHandle* out_handle) {
return insert_sound_table_stream_core(ctx, stream_id, false, info, out_handle);
}
ModResult add_sound_table_stream(ModContext* ctx, AudioSoundTableStreamInfo const* info,
AudioSoundTableHandle* out_handle, uint16_t* out_stream_id) {
if (out_stream_id == nullptr) {
return MOD_INVALID_ARGUMENT;
}
auto const stream_id = stream_id_allocator.alloc();
auto const result = insert_sound_table_stream_core(ctx, stream_id, true, info, out_handle);
if (result != MOD_OK) {
stream_id_allocator.free(stream_id);
}
*out_stream_id = stream_id;
return result;
}
static PlainIdAllocator<u16>& id_allocator_for(SoundTableReplacementSlot const* slot) {
if (dynamic_cast<StreamReplacementSlot const*>(slot))
return stream_id_allocator;
if (auto const se = dynamic_cast<SoundEffectReplacementSlot const*>(slot))
return sound_effect_id_allocator[se->id];
CRASH("Unknown type???");
}
static bool sound_table_remove(LoadedMod const& mod, AudioSoundTableHandle const handle) {
auto const found = sound_replacements.find_owned(handle, mod);
if (found == nullptr) {
return false;
}
if (found->value->mod_defined) {
auto& allocator = id_allocator_for(found->value.get());
allocator.free(found->value->id);
}
sound_replacements.erase_owned(handle, mod);
return true;
}
ModResult remove_sound_table(ModContext* ctx, AudioSoundTableHandle handle) {
auto* mod = mod_from_context(ctx);
if (mod == nullptr || handle == 0) {
return MOD_INVALID_ARGUMENT;
}
if (!sound_table_remove(*mod, handle)) {
Log.error("[{}] remove sound table failed: unknown handle {}", mod->metadata.id, handle);
return MOD_INVALID_ARGUMENT;
}
return MOD_OK;
}
} // namespace dusk::mods::svc::audio_res::bst
+99
View File
@@ -0,0 +1,99 @@
#pragma once
#include <absl/container/flat_hash_map.h>
#include <mutex>
#include "JSystem/JAudio2/JAUSoundTable.h"
#include "mods/svc/audio_res.h"
namespace dusk::mods {
struct LoadedMod;
}
namespace dusk::mods::svc::audio_res::bst {
struct SoundTableReplacementSlot {
bool mod_defined;
u16 id;
JAUSoundTableItem item;
SoundTableReplacementSlot(bool mod_defined, u16 id);
virtual ~SoundTableReplacementSlot() = 0;
[[nodiscard]] virtual u8 get_type_id() const = 0;
};
struct SoundEffectReplacementSlot final : SoundTableReplacementSlot {
SoundEffectCategory category;
SoundEffectReplacementSlot(bool mod_defined, u16 id, SoundEffectCategory category,
const AudioSoundTableEffectInfo& info);
~SoundEffectReplacementSlot() override = default;
[[nodiscard]] u8 get_type_id() const override;
};
struct StreamReplacementSlot final : SoundTableReplacementSlot {
std::string file_path;
bool stop_on_scene_change;
StreamReplacementSlot(bool mod_defined, u16 id, const AudioSoundTableStreamInfo& info);
~StreamReplacementSlot() override = default;
[[nodiscard]] u8 get_type_id() const override;
};
struct SoundEffectKey {
SoundEffectCategory category;
u16 id;
template <typename H>
friend H AbslHashValue(H h, const SoundEffectKey& k) {
return H::combine(std::move(h), k.category, k.id);
}
[[nodiscard]] bool operator==(const SoundEffectKey& other) const {
return other.category == category && other.id == id;
}
};
std::shared_ptr<SoundTableReplacementSlot> get_override_for(JAISoundID id);
std::shared_ptr<SoundEffectReplacementSlot> get_override_for_se(JAISoundID id);
std::shared_ptr<StreamReplacementSlot> get_override_for_stream(JAISoundID id);
void frame_end();
void remove_mod(LoadedMod const& mod);
void sync_audio_replacements();
ModResult replace_sound_table_effect(
ModContext* ctx,
SoundEffectCategory category_id,
uint16_t effect_id,
AudioSoundTableEffectInfo const* info,
AudioSoundTableHandle* out_handle);
ModResult add_sound_table_effect(
ModContext* ctx,
SoundEffectCategory category_id,
AudioSoundTableEffectInfo const* info,
AudioSoundTableHandle* out_handle,
uint16_t* out_effect_id);
ModResult replace_sound_table_stream(
ModContext* ctx,
uint16_t stream_id,
AudioSoundTableStreamInfo const* info,
AudioSoundTableHandle* out_handle);
ModResult add_sound_table_stream(
ModContext* ctx,
AudioSoundTableStreamInfo const* info,
AudioSoundTableHandle* out_handle,
uint16_t* out_stream_id);
ModResult remove_sound_table(ModContext* ctx, AudioSoundTableHandle handle);
}
+1 -1
View File
@@ -14,7 +14,7 @@ class PlainIdAllocator {
T alloc_max;
public:
explicit PlainIdAllocator(T first, T max=std::numeric_limits<T>::max())
constexpr explicit PlainIdAllocator(T first, T max=std::numeric_limits<T>::max())
: alloc_next(first), alloc_max(max) {
}