mirror of
https://github.com/TwilitRealm/dusklight
synced 2026-08-25 22:46:32 -04:00
BST SE/STREAM replacement support
No SEQ yet since idk how I wanna handle it.
This commit is contained in:
@@ -1487,6 +1487,8 @@ set(DUSK_FILES
|
||||
src/dusk/mods/manifest.hpp
|
||||
src/dusk/mods/svc/audio_res/audio_res.hpp
|
||||
src/dusk/mods/svc/audio_res/audio_res.cpp
|
||||
src/dusk/mods/svc/audio_res/bst.cpp
|
||||
src/dusk/mods/svc/audio_res/bst.hpp
|
||||
src/dusk/mods/svc/audio_res/wsys.cpp
|
||||
src/dusk/mods/svc/audio_res/wsys.hpp
|
||||
src/dusk/mods/svc/audio_res/wave.cpp
|
||||
|
||||
@@ -266,7 +266,8 @@ struct Z2Audience : public JAIAudience, public JASGlobalInstance<Z2Audience> {
|
||||
|
||||
virtual ~Z2Audience();
|
||||
virtual JAIAudible* newAudible(const JGeometry::TVec3<f32>& pos, JAISoundID soundID,
|
||||
const JGeometry::TVec3<f32>*, u32);
|
||||
const JGeometry::TVec3<f32>*, u32
|
||||
IF_DUSK_ARG(dusk::mods::svc::audio_res::bst::SoundTableReplacementSlot const*));
|
||||
virtual int getMaxChannels();
|
||||
virtual void deleteAudible(JAIAudible* audible);
|
||||
virtual u32 calcPriority(JAIAudible* audible);
|
||||
|
||||
@@ -6,23 +6,29 @@
|
||||
#include "JSystem/JAudio2/JAUSoundInfo.h"
|
||||
#include "JSystem/JAudio2/JAUSoundTable.h"
|
||||
|
||||
#define STRM_CH_SHIFT_ 2
|
||||
|
||||
#define STRM_CH_CENTER 1
|
||||
#define STRM_CH_LEFT 2
|
||||
#define STRM_CH_RIGHT 3
|
||||
|
||||
class Z2SoundInfo : public JAISoundInfo, public JAUSoundInfo, public JAIStreamDataMgr, public JASGlobalInstance<Z2SoundInfo> {
|
||||
public:
|
||||
Z2SoundInfo() : JAISoundInfo(true), JAUSoundInfo(true), JASGlobalInstance<Z2SoundInfo>(true) {}
|
||||
virtual u16 getAudibleSw(JAISoundID soundID) const;
|
||||
virtual u16 getAudibleSw(JAISoundID soundID IF_DUSK_ARG(SoundTableReplacementSlot const* replacement)) const;
|
||||
virtual u16 getBgmSeqResourceID(JAISoundID soundID) const;
|
||||
virtual s32 getStreamFileEntry(JAISoundID soundID);
|
||||
virtual s32 getStreamFileEntry(JAISoundID soundID IF_DUSK_ARG(StreamReplacementSlot const* replacement));
|
||||
virtual int getSoundType(JAISoundID soundID) const;
|
||||
virtual int getCategory(JAISoundID soundID) const;
|
||||
virtual u32 getPriority(JAISoundID soundID) const;
|
||||
virtual void getSeInfo(JAISoundID soundID, JAISe* sePtr) const;
|
||||
virtual u32 getPriority(JAISoundID soundID IF_DUSK_ARG(SoundTableReplacementSlot const* replacement)) const;
|
||||
virtual void getSeInfo(JAISoundID soundID, JAISe* sePtr IF_DUSK_ARG(SoundEffectReplacementSlot const* replacement)) const;
|
||||
virtual void getSeqInfo(JAISoundID soundID, JAISeq* seqPtr) const;
|
||||
virtual void getStreamInfo(JAISoundID soundID, JAIStream* streamPtr) const;
|
||||
virtual void getStreamInfo(JAISoundID soundID, JAIStream* streamPtr IF_DUSK_ARG(StreamReplacementSlot const* replacement)) const;
|
||||
virtual ~Z2SoundInfo() {}
|
||||
|
||||
JAUAudibleParam getAudibleSwFull(JAISoundID soundID);
|
||||
const char* getStreamFilePath(JAISoundID soundID);
|
||||
int getSwBit(JAISoundID soundID) const;
|
||||
JAUAudibleParam getAudibleSwFull(JAISoundID soundID IF_DUSK_ARG(SoundTableReplacementSlot const* replacement));
|
||||
const char* getStreamFilePath(JAISoundID soundID IF_DUSK_ARG(StreamReplacementSlot const* replacement));
|
||||
int getSwBit(JAISoundID soundID IF_DUSK_ARG(SoundTableReplacementSlot const* replacement)) const;
|
||||
void getSoundInfo_(JAISoundID soundID, JAISound* soundPtr) const;
|
||||
|
||||
BOOL isValid() const {
|
||||
|
||||
@@ -42,7 +42,7 @@ private:
|
||||
/* 0x004 */ JAISeMgr seMgr_;
|
||||
/* 0x728 */ JAISeqMgr seqMgr_;
|
||||
/* 0x79C */ JAIStreamMgr streamMgr_;
|
||||
/* 0x80C */ JAISoundID soundID_;
|
||||
/* 0x80C */ JAISoundID bgmMuter;
|
||||
}; // Size: 0x810
|
||||
|
||||
#if VERSION != VERSION_SHIELD_DEBUG
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
|
||||
#include "JSystem/JGeometry.h"
|
||||
|
||||
namespace dusk::mods::svc::audio_res::bst {
|
||||
struct SoundTableReplacementSlot;
|
||||
}
|
||||
|
||||
class JAIAudible;
|
||||
class JAISoundID;
|
||||
struct JASSoundParams;
|
||||
@@ -14,7 +18,8 @@ struct JASSoundParams;
|
||||
struct JAIAudience {
|
||||
virtual ~JAIAudience();
|
||||
virtual JAIAudible* newAudible(JGeometry::TVec3<f32> const&, JAISoundID,
|
||||
JGeometry::TVec3<f32> const*, u32) = 0;
|
||||
JGeometry::TVec3<f32> const*, u32
|
||||
IF_DUSK_ARG(dusk::mods::svc::audio_res::bst::SoundTableReplacementSlot const*)) = 0;
|
||||
virtual int getMaxChannels() = 0;
|
||||
virtual void deleteAudible(JAIAudible*) = 0;
|
||||
virtual u32 calcPriority(JAIAudible*) = 0;
|
||||
|
||||
@@ -43,7 +43,7 @@ public:
|
||||
void startTrack_(const JASSoundParams& params);
|
||||
void JAISeCategoryMgr_mixOut_(bool, const JASSoundParams& params, JAISoundActivity activity);
|
||||
void JAISeCategoryMgr_calc_();
|
||||
void JAISeMgr_startID_(JAISoundID id, const JGeometry::TVec3<f32>* posPtr, JAIAudience* audience);
|
||||
void JAISeMgr_startID_(JAISoundID id, const JGeometry::TVec3<f32>* posPtr, JAIAudience* audience IF_DUSK_ARG(std::shared_ptr<SoundEffectReplacementSlot> replacement));
|
||||
bool prepare_getSeqData_();
|
||||
void prepare_();
|
||||
|
||||
|
||||
@@ -104,7 +104,7 @@ public:
|
||||
JAISe* newSe_(int category, u32 priority);
|
||||
void calc();
|
||||
void mixOut();
|
||||
bool startSound(JAISoundID id, JAISoundHandle* handle, const JGeometry::TVec3<f32>* posPtr);
|
||||
bool startSound(JAISoundID id, JAISoundHandle* handle, const JGeometry::TVec3<f32>* posPtr IF_DUSK_ARG(std::shared_ptr<dusk::mods::svc::audio_res::bst::SoundEffectReplacementSlot> replacement));
|
||||
int getNumActiveSe() const;
|
||||
|
||||
/* 0x004 */ JAISoundActivity mSoundActivity;
|
||||
|
||||
@@ -6,7 +6,16 @@
|
||||
#include "JSystem/JUtility/JUTAssert.h"
|
||||
#include "global.h"
|
||||
#include "helpers/endian.h"
|
||||
#include <cstdint>
|
||||
|
||||
#if TARGET_PC
|
||||
#include <memory>
|
||||
|
||||
namespace dusk::mods::svc::audio_res::bst {
|
||||
struct SoundTableReplacementSlot;
|
||||
struct SoundEffectReplacementSlot;
|
||||
struct StreamReplacementSlot;
|
||||
}
|
||||
#endif
|
||||
|
||||
class JAISound;
|
||||
|
||||
@@ -271,10 +280,16 @@ class JAITempoMgr;
|
||||
*/
|
||||
class JAISound {
|
||||
public:
|
||||
#if TARGET_PC
|
||||
using SoundTableReplacementSlot = dusk::mods::svc::audio_res::bst::SoundTableReplacementSlot;
|
||||
using SoundEffectReplacementSlot = dusk::mods::svc::audio_res::bst::SoundEffectReplacementSlot;
|
||||
using StreamReplacementSlot = dusk::mods::svc::audio_res::bst::StreamReplacementSlot;
|
||||
#endif
|
||||
|
||||
void releaseHandle();
|
||||
void attachHandle(JAISoundHandle* handle);
|
||||
JAISound();
|
||||
void start_JAISound_(JAISoundID id, const JGeometry::TVec3<f32>* posPtr, JAIAudience* audience);
|
||||
void start_JAISound_(JAISoundID id, const JGeometry::TVec3<f32>* posPtr, JAIAudience* audience IF_DUSK_ARG(std::shared_ptr<SoundTableReplacementSlot> replacement));
|
||||
bool acceptsNewAudible() const;
|
||||
void newAudible(const JGeometry::TVec3<f32>&, JGeometry::TVec3<f32> const*, u32,
|
||||
JAIAudience*);
|
||||
@@ -297,6 +312,11 @@ public:
|
||||
virtual bool JAISound_tryDie_() = 0;
|
||||
|
||||
JAISoundID getID() const { return soundID_; }
|
||||
#if TARGET_PC
|
||||
SoundTableReplacementSlot* getReplacement() const {
|
||||
return replacement.get();
|
||||
}
|
||||
#endif
|
||||
u32 getAnimationState() const { return status_.state.flags.animationState; }
|
||||
bool isAnimated() const { return getAnimationState() != 0; }
|
||||
void setAnimationState(u32 state) {
|
||||
@@ -380,6 +400,9 @@ public:
|
||||
/* 0x34 */ u32 priority_;
|
||||
/* 0x38 */ s32 count_;
|
||||
/* 0x3C */ JAISoundParams params_;
|
||||
#if TARGET_PC
|
||||
std::shared_ptr<SoundTableReplacementSlot> replacement;
|
||||
#endif
|
||||
}; // Size: 0x98
|
||||
|
||||
STATIC_ASSERT(sizeof(JAISound) == 0x98);
|
||||
|
||||
@@ -9,13 +9,17 @@
|
||||
*
|
||||
*/
|
||||
struct JAISoundInfo : public JASGlobalInstance<JAISoundInfo> {
|
||||
IF_DUSK(using SoundTableReplacementSlot = dusk::mods::svc::audio_res::bst::SoundTableReplacementSlot);
|
||||
IF_DUSK(using SoundEffectReplacementSlot = dusk::mods::svc::audio_res::bst::SoundEffectReplacementSlot);
|
||||
IF_DUSK(using StreamReplacementSlot = dusk::mods::svc::audio_res::bst::StreamReplacementSlot);
|
||||
|
||||
JAISoundInfo(bool);
|
||||
virtual int getSoundType(JAISoundID) const = 0;
|
||||
virtual int getCategory(JAISoundID) const = 0;
|
||||
virtual u32 getPriority(JAISoundID) const = 0;
|
||||
virtual void getSeInfo(JAISoundID, JAISe*) const = 0;
|
||||
virtual u32 getPriority(JAISoundID IF_DUSK_ARG(SoundTableReplacementSlot const* replacement)) const = 0;
|
||||
virtual void getSeInfo(JAISoundID, JAISe* IF_DUSK_ARG(SoundEffectReplacementSlot const* replacement)) const = 0;
|
||||
virtual void getSeqInfo(JAISoundID, JAISeq*) const = 0;
|
||||
virtual void getStreamInfo(JAISoundID, JAIStream*) const = 0;
|
||||
virtual void getStreamInfo(JAISoundID, JAIStream* IF_DUSK_ARG(StreamReplacementSlot const* replacement)) const = 0;
|
||||
virtual ~JAISoundInfo();
|
||||
};
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ public:
|
||||
JAIStream(JAIStreamMgr* streamMgr, JAISoundStrategyMgr<JAIStream>* soundStrategyMgr);
|
||||
void JAIStreamMgr_startID_(JAISoundID id, s32 streamFileEntry,
|
||||
const JGeometry::TVec3<f32>* posPtr, JAIAudience* audience,
|
||||
int category);
|
||||
int category IF_DUSK_ARG(std::shared_ptr<StreamReplacementSlot> replacement));
|
||||
bool prepare_prepareStream_();
|
||||
void prepare_();
|
||||
void prepare_startStream_();
|
||||
|
||||
@@ -8,7 +8,9 @@
|
||||
*
|
||||
*/
|
||||
struct JAIStreamDataMgr {
|
||||
virtual s32 getStreamFileEntry(JAISoundID) = 0;
|
||||
IF_DUSK(using StreamReplacementSlot2 = dusk::mods::svc::audio_res::bst::StreamReplacementSlot);
|
||||
|
||||
virtual s32 getStreamFileEntry(JAISoundID IF_DUSK_ARG(StreamReplacementSlot2 const*)) = 0;
|
||||
virtual ~JAIStreamDataMgr();
|
||||
};
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ struct JAIStreamDataMgr;
|
||||
class JAIStreamMgr : public JASGlobalInstance<JAIStreamMgr> {
|
||||
public:
|
||||
JAIStreamMgr(bool setInstance);
|
||||
bool startSound(JAISoundID id, JAISoundHandle* handle, const JGeometry::TVec3<f32>* posPtr);
|
||||
bool startSound(JAISoundID id, JAISoundHandle* handle, const JGeometry::TVec3<f32>* posPtr IF_DUSK_ARG(std::shared_ptr<dusk::mods::svc::audio_res::bst::StreamReplacementSlot> replacement));
|
||||
void freeDeadStream_();
|
||||
void calc();
|
||||
void stop();
|
||||
|
||||
@@ -10,8 +10,10 @@
|
||||
*/
|
||||
class JAUSoundInfo : public JASGlobalInstance<JAUSoundInfo> {
|
||||
public:
|
||||
IF_DUSK(using SoundTableReplacementSlot2 = dusk::mods::svc::audio_res::bst::SoundTableReplacementSlot);
|
||||
|
||||
JAUSoundInfo(bool param_0) : JASGlobalInstance<JAUSoundInfo>(param_0) {}
|
||||
virtual u16 getAudibleSw(JAISoundID) const = 0;
|
||||
virtual u16 getAudibleSw(JAISoundID IF_DUSK_ARG(SoundTableReplacementSlot2 const*)) const = 0;
|
||||
virtual u16 getBgmSeqResourceID(JAISoundID) const = 0;
|
||||
};
|
||||
|
||||
|
||||
@@ -51,6 +51,11 @@
|
||||
*/
|
||||
#define SOUND_SW_IGNORE_FX_MIX 0x0000'0004
|
||||
|
||||
/**
|
||||
* Mute all BGM sequences while this sound is playing.
|
||||
*/
|
||||
#define SOUND_SW_MUTE_BGM 0x0000'0008
|
||||
|
||||
/**
|
||||
* Offset to shift to access @see SOUND_SW_RANDOM_PITCH_MASK
|
||||
*/
|
||||
@@ -82,10 +87,21 @@
|
||||
*/
|
||||
#define SOUND_SW_IGNORE_DOLBY 0x0000'2000
|
||||
|
||||
/**
|
||||
* Unsure. Relates to Z2 pooling of sound handles.
|
||||
*/
|
||||
#define SOUND_SW_POOL_FLAG_1 0x0000'4000
|
||||
|
||||
/**
|
||||
* Unsure. Relates to Z2 pooling of sound handles.
|
||||
*/
|
||||
#define SOUND_SW_POOL_FLAG_2 0x0000'8000
|
||||
|
||||
/**
|
||||
* 3-bit mask used to select a volume distance/falloff class for this sound.
|
||||
*/
|
||||
#define SOUND_SW_VOL_DIST_BIT_MASK 0x0007'0000
|
||||
#define SOUND_SW_VOL_DIST_BIT_OFFSET 16
|
||||
|
||||
/**
|
||||
* Limit minimum volume of this sound (after distance falloff) to 0.2.
|
||||
@@ -97,6 +113,7 @@
|
||||
* @see SOUND_SW_VOL_DIST_BIT_MASK must be zero for this to work.
|
||||
*/
|
||||
#define SOUND_SW_VOL_DIST_BIT_2_MASK 0x0070'0000
|
||||
#define SOUND_SW_VOL_DIST_BIT_2_OFFSET 20
|
||||
|
||||
/**
|
||||
* Mark sound as "far away" or "culled" when at max distance (selected by distance class).
|
||||
@@ -290,13 +307,17 @@ struct JAUSoundTableGroup {
|
||||
*
|
||||
*/
|
||||
struct JAUSoundTable : public JASGlobalInstance<JAUSoundTable> {
|
||||
#if TARGET_PC
|
||||
using SoundTableReplacementSlot = dusk::mods::svc::audio_res::bst::SoundTableReplacementSlot;
|
||||
#endif
|
||||
|
||||
JAUSoundTable(bool setInstance) : JASGlobalInstance<JAUSoundTable>(setInstance) {
|
||||
}
|
||||
~JAUSoundTable() {}
|
||||
|
||||
void init(void const*);
|
||||
u8 getTypeID(JAISoundID) const;
|
||||
JAUSoundTableItem* getData(JAISoundID) const;
|
||||
u8 getTypeID(JAISoundID IF_DUSK_ARG(SoundTableReplacementSlot const*)) const;
|
||||
JAUSoundTableItem DUSK_CONST* getData(JAISoundID IF_DUSK_ARG(SoundTableReplacementSlot const*)) const;
|
||||
int getNumGroups_inSection(u8) const;
|
||||
int getNumItems_inGroup(u8, u8) const;
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ struct JAUStreamFileTable {
|
||||
*
|
||||
*/
|
||||
struct JAUStreamDataMgr_StreamFileTable : public JAIStreamDataMgr, JAUStreamFileTable {
|
||||
virtual s32 getStreamFileEntry(JAISoundID);
|
||||
virtual s32 getStreamFileEntry(JAISoundID IF_DUSK_ARG(StreamReplacementSlot2 const*));
|
||||
virtual ~JAUStreamDataMgr_StreamFileTable() {}
|
||||
};
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "JSystem/JAudio2/JAISe.h"
|
||||
#include "JSystem/JAudio2/JAIAudience.h"
|
||||
#include "JSystem/JAudio2/JAISeMgr.h"
|
||||
#include "dusk/mods/svc/audio_res/bst.hpp"
|
||||
|
||||
JAISe::JAISe(JAISeMgr* seMgr, JAISoundStrategyMgr<JAISe>* soundStrategyMgr, u32 priority) : JSULink<JAISe>(this) {
|
||||
inner_.mSoundStrategyMgr = soundStrategyMgr;
|
||||
@@ -129,10 +130,10 @@ bool JAISe::JAISound_tryDie_() {
|
||||
return false;
|
||||
}
|
||||
|
||||
void JAISe::JAISeMgr_startID_(JAISoundID id, const JGeometry::TVec3<f32>* posPtr, JAIAudience* audience) {
|
||||
void JAISe::JAISeMgr_startID_(JAISoundID id, const JGeometry::TVec3<f32>* posPtr, JAIAudience* audience IF_DUSK_ARG(std::shared_ptr<SoundEffectReplacementSlot> replacement)) {
|
||||
JUT_ASSERT(221, inner_.track.getStatus() == JASTrack::STATUS_FREE);
|
||||
|
||||
start_JAISound_(id, posPtr, audience);
|
||||
start_JAISound_(id, posPtr, audience IF_DUSK_ARG(std::static_pointer_cast<SoundTableReplacementSlot>(replacement)));
|
||||
inner_.field_0x26c = 0;
|
||||
if (inner_.mSoundStrategyMgr) {
|
||||
inner_.field_0x278 = inner_.mSoundStrategyMgr->calc(id);
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "JSystem/JAudio2/JAISoundHandles.h"
|
||||
#include "JSystem/JAudio2/JAISoundInfo.h"
|
||||
#include "JSystem/JAudio2/JASReport.h"
|
||||
#include "dusk/mods/svc/audio_res/bst.hpp"
|
||||
|
||||
bool JAISeCategoryMgr::isUsingSeqData(const JAISeqDataRegion& seqDataRegion) {
|
||||
{
|
||||
@@ -284,7 +285,7 @@ void JAISeMgr::mixOut() {
|
||||
}
|
||||
}
|
||||
|
||||
bool JAISeMgr::startSound(JAISoundID id, JAISoundHandle* handle, const JGeometry::TVec3<f32>* posPtr) {
|
||||
bool JAISeMgr::startSound(JAISoundID id, JAISoundHandle* handle, const JGeometry::TVec3<f32>* posPtr IF_DUSK_ARG(std::shared_ptr<dusk::mods::svc::audio_res::bst::SoundEffectReplacementSlot> replacement)) {
|
||||
if (handle && *handle) {
|
||||
(*handle)->stop();
|
||||
}
|
||||
@@ -294,7 +295,7 @@ bool JAISeMgr::startSound(JAISoundID id, JAISoundHandle* handle, const JGeometry
|
||||
u32 category;
|
||||
if (soundInfoPtr != NULL) {
|
||||
category = soundInfoPtr->getCategory(id);
|
||||
priority = soundInfoPtr->getPriority(id);
|
||||
priority = soundInfoPtr->getPriority(id IF_DUSK_ARG(replacement.get()));
|
||||
} else {
|
||||
category = id.id_.info.type.parts.groupID;
|
||||
priority = 0;
|
||||
@@ -309,10 +310,10 @@ bool JAISeMgr::startSound(JAISoundID id, JAISoundHandle* handle, const JGeometry
|
||||
}
|
||||
|
||||
JAIAudience* audiencePtr = getAudience(category);
|
||||
se->JAISeMgr_startID_(id, posPtr, audiencePtr);
|
||||
se->JAISeMgr_startID_(id, posPtr, audiencePtr IF_DUSK_ARG(replacement));
|
||||
|
||||
if (soundInfoPtr != NULL) {
|
||||
soundInfoPtr->getSeInfo(id, se);
|
||||
soundInfoPtr->getSeInfo(id, se IF_DUSK_ARG(replacement.get()));
|
||||
}
|
||||
|
||||
if (handle != NULL) {
|
||||
|
||||
@@ -28,7 +28,7 @@ void JAISeq::JAISeqMgr_startID_(JAISoundID id, const JGeometry::TVec3<f32>* posP
|
||||
JAIAudience* audience, int category, int param_4) {
|
||||
inner_.field_0x39c = category;
|
||||
reserveChildTracks_(param_4);
|
||||
start_JAISound_(id, posPtr, audience);
|
||||
start_JAISound_(id, posPtr, audience IF_DUSK_ARG(nullptr));
|
||||
|
||||
if (inner_.strategyMgr) {
|
||||
field_0x3a8 = inner_.strategyMgr->calc(id);
|
||||
|
||||
@@ -63,7 +63,7 @@ void JAISoundParams::mixOutAll(const JASSoundParams& inParams, JASSoundParams* o
|
||||
|
||||
JAISound::JAISound() : params_() {}
|
||||
|
||||
void JAISound::start_JAISound_(JAISoundID id, const JGeometry::TVec3<f32>* posPtr, JAIAudience* audience) {
|
||||
void JAISound::start_JAISound_(JAISoundID id, const JGeometry::TVec3<f32>* posPtr, JAIAudience* audience IF_DUSK_ARG(std::shared_ptr<SoundTableReplacementSlot> replacement)) {
|
||||
handle_ = NULL;
|
||||
soundID_ = id;
|
||||
status_.init();
|
||||
@@ -72,9 +72,10 @@ void JAISound::start_JAISound_(JAISoundID id, const JGeometry::TVec3<f32>* posPt
|
||||
audience_ = audience;
|
||||
prepareCount_ = 0;
|
||||
count_ = 0;
|
||||
IF_DUSK(this->replacement = std::move(replacement));
|
||||
|
||||
if (posPtr != NULL && audience_ != NULL) {
|
||||
audible_ = audience_->newAudible(*posPtr, soundID_, NULL, 0);
|
||||
audible_ = audience_->newAudible(*posPtr, soundID_, NULL, 0 IF_DUSK_ARG(getReplacement()));
|
||||
} else {
|
||||
audible_ = NULL;
|
||||
}
|
||||
@@ -98,7 +99,7 @@ void JAISound::newAudible(const JGeometry::TVec3<f32>& pos,
|
||||
}
|
||||
|
||||
JUT_ASSERT(157, audience_);
|
||||
audible_ = audience_->newAudible(pos, soundID_, param_1, param_2);
|
||||
audible_ = audience_->newAudible(pos, soundID_, param_1, param_2 IF_DUSK_ARG(getReplacement()));
|
||||
}
|
||||
|
||||
void JAISound::stop(u32 fadeTime) {
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "JSystem/JAudio2/JAISoundChild.h"
|
||||
#include "JSystem/JAudio2/JAIStreamDataMgr.h"
|
||||
#include "JSystem/JAudio2/JAIAudience.h"
|
||||
#include "dusk/mods/svc/audio_res/bst.hpp"
|
||||
|
||||
static void JAIStream_JASAramStreamCallback_(u32 type, JASAramStream* aramStream, void* userData) {
|
||||
JAIStream* stream = (JAIStream*)userData;
|
||||
@@ -34,10 +35,10 @@ JAIStream::JAIStream(JAIStreamMgr* streamMgr, JAISoundStrategyMgr<JAIStream>* so
|
||||
|
||||
void JAIStream::JAIStreamMgr_startID_(JAISoundID id, s32 streamFileEntry,
|
||||
const JGeometry::TVec3<f32>* posPtr, JAIAudience* audience,
|
||||
int category) {
|
||||
int category IF_DUSK_ARG(std::shared_ptr<dusk::mods::svc::audio_res::bst::StreamReplacementSlot> replacement)) {
|
||||
field_0x298 = category;
|
||||
field_0x294 = streamFileEntry;
|
||||
start_JAISound_(id, posPtr, audience);
|
||||
start_JAISound_(id, posPtr, audience IF_DUSK_ARG(std::static_pointer_cast<SoundTableReplacementSlot>(replacement)));
|
||||
field_0x290 = 0;
|
||||
|
||||
if (field_0x2c0 != NULL) {
|
||||
|
||||
@@ -14,13 +14,13 @@ JAIStreamMgr::JAIStreamMgr(bool setInstance) : JASGlobalInstance<JAIStreamMgr>(s
|
||||
mActivity.init();
|
||||
}
|
||||
|
||||
bool JAIStreamMgr::startSound(JAISoundID id, JAISoundHandle* handle, const JGeometry::TVec3<f32>* posPtr) {
|
||||
bool JAIStreamMgr::startSound(JAISoundID id, JAISoundHandle* handle, const JGeometry::TVec3<f32>* posPtr IF_DUSK_ARG(std::shared_ptr<dusk::mods::svc::audio_res::bst::StreamReplacementSlot> replacement)) {
|
||||
JUT_ASSERT(37, streamDataMgr_);
|
||||
if (handle != NULL && *handle) {
|
||||
(*handle)->stop();
|
||||
}
|
||||
|
||||
s32 streamFileEntry = streamDataMgr_->getStreamFileEntry(id);
|
||||
s32 streamFileEntry = streamDataMgr_->getStreamFileEntry(id IF_DUSK_ARG(replacement.get()));
|
||||
if (streamFileEntry < 0) {
|
||||
JUT_WARN(46, "Cannot find the stream file entry for ID:%08x\n", id.id_.composite_)
|
||||
return false;
|
||||
@@ -38,9 +38,9 @@ bool JAIStreamMgr::startSound(JAISoundID id, JAISoundHandle* handle, const JGeom
|
||||
return false;
|
||||
}
|
||||
|
||||
stream->JAIStreamMgr_startID_(id, streamFileEntry, posPtr, mAudience, category);
|
||||
stream->JAIStreamMgr_startID_(id, streamFileEntry, posPtr, mAudience, category IF_DUSK_ARG(replacement));
|
||||
if (soundInfo != NULL) {
|
||||
soundInfo->getStreamInfo(id, stream);
|
||||
soundInfo->getStreamInfo(id, stream IF_DUSK_ARG(replacement.get()));
|
||||
}
|
||||
|
||||
if (handle != NULL) {
|
||||
|
||||
@@ -47,7 +47,12 @@ namespace {
|
||||
mStreamFileDVDEntryNums[i] = DVDConvertPathToEntrynum(stack_14.getFilePath(i));
|
||||
}
|
||||
}
|
||||
virtual s32 getStreamFileEntry(JAISoundID id) {
|
||||
virtual s32 getStreamFileEntry(JAISoundID id IF_DUSK_ARG(StreamReplacementSlot2 const* replacement)) {
|
||||
#if TARGET_PC
|
||||
if (replacement) {
|
||||
CRASH("TStreamDataMgr::getStreamFileEntry not implemented for replacements");
|
||||
}
|
||||
#endif
|
||||
u32 short_id = id.id_.info.waveID;
|
||||
if (short_id >= mNumStreamFiles) {
|
||||
return -1;
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
|
||||
#include "JSystem/JAudio2/JAUSoundTable.h"
|
||||
|
||||
#include "dusk/mods/svc/audio_res/bst.hpp"
|
||||
|
||||
void JAUSoundTable::init(void const* param_0) {
|
||||
if (param_0 != NULL) {
|
||||
field_0x0.init(param_0);
|
||||
@@ -14,11 +16,16 @@ void JAUSoundTable::init(void const* param_0) {
|
||||
}
|
||||
}
|
||||
|
||||
u8 JAUSoundTable::getTypeID(JAISoundID param_0) const {
|
||||
u8 JAUSoundTable::getTypeID(JAISoundID param_0 IF_DUSK_ARG(SoundTableReplacementSlot const* replacement)) const {
|
||||
#if DUSK_AUDIO_DISABLED
|
||||
if (this == NULL) {
|
||||
return 0xff;
|
||||
}
|
||||
#endif
|
||||
#if TARGET_PC
|
||||
if (replacement) {
|
||||
return replacement->get_type_id();
|
||||
}
|
||||
#endif
|
||||
if (param_0.isAnonymous()) {
|
||||
return 0xff;
|
||||
@@ -34,11 +41,16 @@ u8 JAUSoundTable::getTypeID(JAISoundID param_0) const {
|
||||
return group->getTypeID(param_0.id_.info.waveID);
|
||||
}
|
||||
|
||||
JAUSoundTableItem* JAUSoundTable::getData(JAISoundID param_0) const {
|
||||
JAUSoundTableItem DUSK_CONST* JAUSoundTable::getData(JAISoundID param_0 IF_DUSK_ARG(SoundTableReplacementSlot const* replacement)) const {
|
||||
#if DUSK_AUDIO_DISABLED
|
||||
if (this == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
#if TARGET_PC
|
||||
if (replacement) {
|
||||
return &replacement->item;
|
||||
}
|
||||
#endif
|
||||
if (param_0.isAnonymous()) {
|
||||
return NULL;
|
||||
|
||||
@@ -31,7 +31,12 @@ const char* JAUStreamFileTable::getFilePath(int index) const {
|
||||
return (char*)(data + *(int*)(data + 8 + (index * sizeof(s32))));
|
||||
}
|
||||
|
||||
s32 JAUStreamDataMgr_StreamFileTable::getStreamFileEntry(JAISoundID soundId) {
|
||||
s32 JAUStreamDataMgr_StreamFileTable::getStreamFileEntry(JAISoundID soundId IF_DUSK_ARG(StreamReplacementSlot2 const* replacement)) {
|
||||
#if TARGET_PC
|
||||
if (replacement) {
|
||||
CRASH("JAUStreamDataMgr_StreamFileTable::getStreamFileEntry not implemented for replacements");
|
||||
}
|
||||
#endif
|
||||
const char* filePath = getFilePath(soundId.id_.info.waveID);
|
||||
if (filePath == NULL) {
|
||||
return -1;
|
||||
|
||||
@@ -13,7 +13,8 @@ if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
|
||||
endif ()
|
||||
|
||||
add_mod(audio_mod
|
||||
SOURCES src/mod.cpp
|
||||
MOD_JSON mod.json
|
||||
RES_DIR res
|
||||
SOURCES src/mod.cpp
|
||||
MOD_JSON mod.json
|
||||
RES_DIR res
|
||||
OVERLAY_DIR overlay
|
||||
)
|
||||
|
||||
@@ -25,6 +25,16 @@ MOD_EXPORT ModResult mod_initialize(ModError*) {
|
||||
"res/go.opus",
|
||||
nullptr,
|
||||
&handle);
|
||||
|
||||
constexpr AudioSoundTableEffectInfo effect(128, 1, 1.5);
|
||||
|
||||
svc_audio_res->replace_sound_table_effect(
|
||||
mod_ctx,
|
||||
SE_CATEGORY_CHARA_SE,
|
||||
0, // MIDNA_APPEAR
|
||||
&effect,
|
||||
nullptr);
|
||||
|
||||
return MOD_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,10 @@
|
||||
#define AUDIO_RES_SERVICE_MAJOR 1u
|
||||
#define AUDIO_RES_SERVICE_MINOR 0u
|
||||
|
||||
/*
|
||||
* WSYS structs
|
||||
*/
|
||||
|
||||
#define AUDIO_RES_DEFAULT_KEY 0x3C;
|
||||
|
||||
typedef enum AudioWaveBank : uint8_t {
|
||||
@@ -21,6 +25,7 @@ typedef enum AudioWaveFormat : uint8_t {
|
||||
} AudioWaveFormat;
|
||||
|
||||
typedef uint64_t AudioWaveHandle;
|
||||
typedef uint64_t AudioSoundTableHandle;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -41,9 +46,68 @@ typedef struct AudioWaveInfo {
|
||||
AudioRawWave const* raw_wave;
|
||||
} AudioWaveInfo;
|
||||
|
||||
/*
|
||||
* BST structs
|
||||
*/
|
||||
|
||||
typedef enum SoundEffectCategory : uint8_t {
|
||||
SE_CATEGORY_SYSTEM_SE,
|
||||
SE_CATEGORY_PLAYER_VOICE,
|
||||
SE_CATEGORY_PLAYER_SE,
|
||||
SE_CATEGORY_FOOTNOTE_SE,
|
||||
SE_CATEGORY_COLLISION_SE,
|
||||
SE_CATEGORY_CHARA_VOICE,
|
||||
SE_CATEGORY_CHARA_SE,
|
||||
SE_CATEGORY_ENEMY_SE,
|
||||
SE_CATEGORY_OBJECT_SE,
|
||||
SE_CATEGORY_ENV_SE
|
||||
} SoundEffectCategory;
|
||||
|
||||
typedef struct AudioSoundTableEffectInfo {
|
||||
uint8_t priority;
|
||||
float volume;
|
||||
float pitch;
|
||||
|
||||
bool always_max_priority;
|
||||
|
||||
bool ignore_distance_volume;
|
||||
bool ignore_distance_fx_mix;
|
||||
bool ignore_pan;
|
||||
bool ignore_dolby;
|
||||
|
||||
uint8_t random_volume;
|
||||
uint8_t random_pitch;
|
||||
|
||||
uint8_t doppler_power;
|
||||
|
||||
uint8_t volume_dist_class;
|
||||
bool clamp_min_volume;
|
||||
bool cull_at_max_distance;
|
||||
} AudioSoundTableEffectInfo;
|
||||
|
||||
typedef enum StreamPan : uint8_t {
|
||||
STREAM_PAN_CENTER,
|
||||
STREAM_PAN_LEFT,
|
||||
STREAM_PAN_RIGHT,
|
||||
} StreamPan;
|
||||
|
||||
#define STREAM_MAX_CHILDREN 6
|
||||
|
||||
typedef struct AudioSoundTableStreamInfo {
|
||||
uint8_t priority;
|
||||
float volume;
|
||||
StreamPan pan_parameters[STREAM_MAX_CHILDREN];
|
||||
char const* file_path;
|
||||
bool stop_on_scene_change;
|
||||
} AudioSoundTableStreamInfo;
|
||||
|
||||
typedef struct AudioResService {
|
||||
ServiceHeader header;
|
||||
|
||||
/*
|
||||
* WSYS API
|
||||
*/
|
||||
|
||||
ModResult (*replace_wave)(
|
||||
ModContext* ctx,
|
||||
AudioWaveBank bank,
|
||||
@@ -61,6 +125,38 @@ typedef struct AudioResService {
|
||||
uint16_t* out_wave_id);
|
||||
|
||||
ModResult (*remove_wave)(ModContext* ctx, AudioWaveHandle handle);
|
||||
|
||||
/*
|
||||
* BST API
|
||||
*/
|
||||
|
||||
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);
|
||||
} AudioResService;
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user