mirror of
https://github.com/zeldaret/ss
synced 2026-06-19 15:40:26 -04:00
Import of more nw4r::snd from https://github.com/kiwi515/ogws
Co-authored-by: kiwi515 <49212064+kiwi515@users.noreply.github.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
# Ignore JSystem Files - Copied From TP
|
||||
**/JSystem/**
|
||||
# Ignore SND Files - Copied from https://github.com/muff1n1634/nw4r_snd_mid2010
|
||||
# Ignore SND Files - Copied from https://github.com/muff1n1634/nw4r_snd_mid2010, https://github.com/kiwi515/ogws
|
||||
**/nw4r/snd/**
|
||||
|
||||
@@ -25202,7 +25202,7 @@ __ct__Q34nw4r3snd15DvdSoundArchiveFv = .text:0x8046BB60; // type:function size:0
|
||||
__dt__Q34nw4r3snd15DvdSoundArchiveFv = .text:0x8046BBB0; // type:function size:0x8C
|
||||
Open__Q34nw4r3snd15DvdSoundArchiveFPCc = .text:0x8046BC40; // type:function size:0x14C
|
||||
Close__Q34nw4r3snd15DvdSoundArchiveFv = .text:0x8046BD90; // type:function size:0x4C
|
||||
fn_8046BDE0 = .text:0x8046BDE0; // type:function size:0xA8
|
||||
OpenStream__Q34nw4r3snd15DvdSoundArchiveCFPviUlUl = .text:0x8046BDE0; // type:function size:0xA8
|
||||
OpenExtStream__Q34nw4r3snd15DvdSoundArchiveCFPviPCcUlUl = .text:0x8046BE90; // type:function size:0xB8
|
||||
detail_GetRequiredStreamBufferSize__Q34nw4r3snd15DvdSoundArchiveCFv = .text:0x8046BF50; // type:function size:0x8
|
||||
LoadHeader__Q34nw4r3snd15DvdSoundArchiveFPvUl = .text:0x8046BF60; // type:function size:0x88
|
||||
@@ -25241,7 +25241,7 @@ Alloc__Q44nw4r3snd6detail9FrameHeapFUlPFPvUlPv_vPv = .text:0x8046CEE0; // type:f
|
||||
SaveState__Q44nw4r3snd6detail9FrameHeapFv = .text:0x8046CF90; // type:function size:0xCC
|
||||
LoadState__Q44nw4r3snd6detail9FrameHeapFi = .text:0x8046D060; // type:function size:0x224
|
||||
GetCurrentLevel__Q44nw4r3snd6detail9FrameHeapCFv = .text:0x8046D290; // type:function size:0xC
|
||||
FUN_8046d2a0 = .text:0x8046D2A0; // type:function size:0x40
|
||||
GetFreeSize__Q44nw4r3snd6detail9FrameHeapCFv = .text:0x8046D2A0; // type:function size:0x40
|
||||
__ct__Q34nw4r3snd15FxReverbStdDpl2Fv = .text:0x8046D2E0; // type:function size:0xC4
|
||||
GetRequiredMemSize__Q34nw4r3snd15FxReverbStdDpl2Fv = .text:0x8046D3B0; // type:function size:0x54
|
||||
AssignWorkBuffer__Q34nw4r3snd15FxReverbStdDpl2FPvUl = .text:0x8046D410; // type:function size:0x8
|
||||
|
||||
@@ -102,12 +102,18 @@ namespace nw4r { namespace snd { namespace detail
|
||||
void SetMasterVolume(f32 volume, int frame);
|
||||
void PrepareReset();
|
||||
|
||||
bool IsResetReady() const {
|
||||
return mResetReadyCounter == 0;
|
||||
}
|
||||
|
||||
private:
|
||||
// cdtors
|
||||
AxManager();
|
||||
|
||||
// callbacks
|
||||
static void AxCallbackFunc();
|
||||
static void AuxCallbackFunc(void* pChans, void* pContext);
|
||||
static void AiDmaCallbackFunc();
|
||||
|
||||
// static members
|
||||
private:
|
||||
@@ -140,7 +146,7 @@ namespace nw4r { namespace snd { namespace detail
|
||||
MoveValue<f32, int> mMasterVolume; // size 0x10, offset 0x1c
|
||||
MoveValue<f32, int> mMainOutVolume; // size 0x10, offset 0x2c
|
||||
MoveValue<f32, int> mVolumeForReset; // size 0x10, offset 0x3c
|
||||
AIDMACallback *mOldAidCallback; // size 0x04, offset 0x4c
|
||||
AIDMACallback mOldAidCallback; // size 0x04, offset 0x4c
|
||||
s32 mResetReadyCounter; // size 0x04, offset 0x50
|
||||
MoveValue<f32, int> mAuxFadeVolume[AUX_BUS_NUM]; // size 0x30, offset 0x54
|
||||
MoveValue<f32, int> mAuxUserVolume[AUX_BUS_NUM]; // size 0x30, offset 0x84
|
||||
|
||||
@@ -47,6 +47,9 @@ namespace nw4r { namespace snd { namespace detail
|
||||
// static members
|
||||
public:
|
||||
static int const VOICE_COUNT_MARGIN = 16;
|
||||
static const int VOICE_MARGIN = 16;
|
||||
static const int VOICE_MAX = AX_VOICE_MAX + VOICE_MARGIN;
|
||||
static const int WORK_SIZE_MAX = VOICE_MAX * sizeof(AxVoice);
|
||||
|
||||
// members
|
||||
private:
|
||||
|
||||
@@ -156,6 +156,13 @@ namespace nw4r { namespace snd { namespace detail
|
||||
// [R89JEL]:/bin/RVL/Debug/mainD.elf:.debug::0x276d8
|
||||
class AmbientParamUpdateCallback
|
||||
{
|
||||
public:
|
||||
enum ParamUpdateFlags {
|
||||
PARAM_UPDATE_VOLUME = (1 << 0),
|
||||
PARAM_UPDATE_PAN = (1 << 1),
|
||||
PARAM_UPDATE_SURROUND_PAN = (1 << 2),
|
||||
PARAM_UPDATE_PRIORITY = (1 << 3),
|
||||
};
|
||||
// methods
|
||||
public:
|
||||
virtual void at_0x08();
|
||||
|
||||
@@ -242,6 +242,10 @@ namespace nw4r { namespace snd { namespace detail
|
||||
// [R89JEL]:/bin/RVL/Debug/mainD.elf:.debug::0x2b895c
|
||||
class ChannelManager
|
||||
{
|
||||
public:
|
||||
static const int VOICE_MARGIN = 1;
|
||||
static const int VOICE_MAX = AX_VOICE_MAX + VOICE_MARGIN;
|
||||
static const int WORK_SIZE_MAX = VOICE_MAX * sizeof(Channel);
|
||||
// methods
|
||||
public:
|
||||
// instance accessors
|
||||
|
||||
@@ -9,38 +9,6 @@ namespace nw4r {
|
||||
namespace snd {
|
||||
namespace detail {
|
||||
|
||||
class ChannelManager {
|
||||
friend class Channel; // Alloc/Free intended through Channel only
|
||||
|
||||
public:
|
||||
static const int VOICE_MARGIN = 1;
|
||||
static const int VOICE_MAX = AX_VOICE_MAX + VOICE_MARGIN;
|
||||
static const int WORK_SIZE_MAX = VOICE_MAX * sizeof(Channel);
|
||||
|
||||
public:
|
||||
static ChannelManager &GetInstance();
|
||||
|
||||
u32 GetRequiredMemSize();
|
||||
|
||||
void Setup(void *pWork, u32 workSize);
|
||||
void Shutdown();
|
||||
void UpdateAllChannel();
|
||||
|
||||
private:
|
||||
ChannelManager();
|
||||
|
||||
Channel *Alloc();
|
||||
void Free(Channel *pChannel);
|
||||
|
||||
private:
|
||||
InstancePool<Channel> mPool; // at 0x0
|
||||
ChannelList mChannelList; // at 0x4
|
||||
bool mInitialized; // at 0x10
|
||||
u32 mChannelCount; // at 0x14
|
||||
void *mMem; // at 0x18
|
||||
u32 mMemSize; // at 0x1C
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
} // namespace snd
|
||||
} // namespace nw4r
|
||||
|
||||
@@ -70,29 +70,6 @@ namespace nw4r { namespace snd
|
||||
DVDFileInfo mFileInfo; // at 0x14C
|
||||
bool mOpen; // at 0x188
|
||||
};
|
||||
|
||||
class DvdSoundArchive::DvdFileStream : public ut::FileStream
|
||||
{
|
||||
DvdFileStream();
|
||||
virtual ut::detail::RuntimeTypeInfo const *GetRuntimeTypeInfo() const { return 0; }
|
||||
virtual void Close() {}
|
||||
virtual s32 Read(void *, u32) { return 0; }
|
||||
virtual bool IsBusy() const { return 0; }
|
||||
virtual bool CanAsync() const { return 0; }
|
||||
virtual bool CanRead() const { return 0; }
|
||||
virtual bool CanWrite() const { return 0; }
|
||||
virtual u32 GetOffsetAlign() const { return 0; }
|
||||
virtual u32 GetSizeAlign() const { return 0; }
|
||||
virtual u32 GetBufferAlign() const { return 0; }
|
||||
virtual u32 GetSize() const { return 0; }
|
||||
virtual void Seek(s32, u32) {}
|
||||
virtual void Cancel() {}
|
||||
virtual bool CancelAsync(StreamCallback *, void *) { return 0; }
|
||||
virtual bool CanSeek() const { return 0; }
|
||||
virtual bool CanCancel() const { return 0; }
|
||||
virtual u32 Tell() const { return 0; }
|
||||
friend class DvdSoundArchive;
|
||||
};
|
||||
}} // namespace nw4r::snd
|
||||
|
||||
#endif // NW4R_SND_DVD_SOUND_ARCHIVE_H
|
||||
|
||||
@@ -19,8 +19,11 @@ namespace nw4r { namespace snd { namespace detail
|
||||
// methods
|
||||
public:
|
||||
// methods
|
||||
ExternalSoundPlayer();
|
||||
~ExternalSoundPlayer();
|
||||
int GetPlayingSoundCount() const { return mSoundList.GetSize(); }
|
||||
int GetPlayableSoundCount() const { return mPlayableCount; }
|
||||
void SetPlayableSoundCount(int count);
|
||||
|
||||
bool AppendSound(BasicSound *sound);
|
||||
void RemoveSound(BasicSound *sound);
|
||||
|
||||
@@ -76,17 +76,17 @@ private:
|
||||
bool mFirstEncodeFlag; // at 0x3
|
||||
bool mValidCallbackFlag; // at 0x4
|
||||
bool mCommandBusyFlag; // at 0x5
|
||||
bool mForceResumeFlag; // at 0x6
|
||||
bool mContinueFlag; // at 0x7
|
||||
// TODO commenting out a random flag to make eggAudioRmtSpeakerMgr match
|
||||
// TODO offsets are wrong as a result
|
||||
// volatile bool mIntervalFlag; // at 0x8
|
||||
// bool mForceResumeFlag; // at 0x6
|
||||
bool mContinueFlag; // at 0x7
|
||||
volatile bool mIntervalFlag; // at 0x8
|
||||
SpeakerState mState; // at 0xC
|
||||
SpeakerCommand mUserCommand; // at 0x10
|
||||
SpeakerCommand mInternalCommand; // at 0x14
|
||||
WENCInfo mEncodeInfo; // at 0x18
|
||||
int mChannelIndex; // at 0x38
|
||||
WPADCallback mWpadCallback; // at 0x3C
|
||||
WPADCallback *mWpadCallback; // at 0x3C
|
||||
OSAlarm mContinueAlarm; // at 0x40
|
||||
OSAlarm mIntervalAlarm; // at 0x70
|
||||
s64 mContinueBeginTime; // at 0xA0
|
||||
|
||||
@@ -21,7 +21,7 @@ public:
|
||||
private:
|
||||
static const int SPEAKER_ALARM_HZ = 150;
|
||||
|
||||
// static const int SPEAKER_ALARM_PERIOD_NSEC = 1.0f / SPEAKER_ALARM_HZ * 1000 * 1000 * 1000;
|
||||
static const int SPEAKER_ALARM_PERIOD_NSEC = static_cast<int>(1.0f / SPEAKER_ALARM_HZ * 1000 * 1000 * 1000);
|
||||
|
||||
private:
|
||||
RemoteSpeakerManager();
|
||||
|
||||
@@ -128,6 +128,7 @@ namespace nw4r { namespace snd { namespace detail
|
||||
SeqTrack *GetPlayerTrack(int trackNo);
|
||||
s16 volatile *GetVariablePtr(int varNo);
|
||||
|
||||
void SetTempoRatio(f32 tempo);
|
||||
void SetReleasePriorityFix(bool fix);
|
||||
void SetChannelPriority(int priority);
|
||||
void SetSeqUserprocCallback(SeqUserprocCallback *callback, void *arg);
|
||||
|
||||
@@ -108,6 +108,7 @@ namespace nw4r { namespace snd { namespace detail
|
||||
s32 GetFileStreamBufferSize() { return sizeof mFileStreamBuffer; }
|
||||
|
||||
void SetReleasePriorityFix(bool fix);
|
||||
void SetTempoRatio(f32 tempo);
|
||||
void SetChannelPriority(int priority);
|
||||
void SetSeqUserprocCallback(SeqPlayer::SeqUserprocCallback *callback,
|
||||
void *arg);
|
||||
|
||||
@@ -15,7 +15,7 @@ class Sound3DManager : public detail::BasicSound::AmbientInfo::AmbientParamUpdat
|
||||
public:
|
||||
struct Sound3DActorParam {
|
||||
u32 userParam; // at 0x0
|
||||
SoundParam soundParam; // at 0x4
|
||||
SoundArchive::Sound3DParam soundParam; // at 0x4
|
||||
math::VEC3 position; // at 0xC
|
||||
|
||||
Sound3DActorParam();
|
||||
|
||||
@@ -119,6 +119,12 @@ namespace nw4r { namespace snd
|
||||
/* 3 bytes padding */
|
||||
}; // size 0x0c
|
||||
|
||||
struct Sound3DParam {
|
||||
u32 flags; // at 0x0
|
||||
u8 decayCurve; // at 0x4
|
||||
u8 decayRatio; // at 0x5
|
||||
};
|
||||
|
||||
// [R89JEL]:/bin/RVL/Debug/mainD.elf:.debug::0x256dc
|
||||
struct SoundArchivePlayerInfo
|
||||
{
|
||||
@@ -170,7 +176,11 @@ namespace nw4r { namespace snd
|
||||
bool IsAvailable() const;
|
||||
SoundType GetSoundType(u32 soundId) const;
|
||||
|
||||
const char* GetSoundLabelString(u32 id) const;
|
||||
u32 ConvertLabelStringToSoundId(char const *label) const;
|
||||
u32 ConvertLabelStringToPlayerId(const char* pLabel) const;
|
||||
u32 ConvertLabelStringToGroupId(const char* pLabel) const;
|
||||
u32 GetSoundUserParam(u32 id) const;
|
||||
|
||||
bool ReadSoundInfo(u32 soundId, SoundInfo *info) const;
|
||||
bool ReadSeqSoundInfo(u32 soundId, SeqSoundInfo *info) const;
|
||||
@@ -192,6 +202,12 @@ namespace nw4r { namespace snd
|
||||
|
||||
ut::FileStream *detail_OpenFileStream(u32 fileId, void *buffer,
|
||||
int size) const;
|
||||
ut::FileStream* detail_OpenGroupStream(u32 id, void* pBuffer,
|
||||
int bufferSize) const;
|
||||
ut::FileStream* detail_OpenGroupWaveDataStream(u32 id, void* pBuffer,
|
||||
int bufferSize) const;
|
||||
|
||||
void SetExternalFileRoot(const char* pExtFileRoot);
|
||||
|
||||
private:
|
||||
ut::FileStream *OpenExtStreamImpl(void *buffer, int size,
|
||||
|
||||
@@ -35,6 +35,8 @@ namespace nw4r { namespace snd { namespace detail
|
||||
u32 fileImageSize; // size 0x04, offset 0x24
|
||||
}; // size 0x28
|
||||
|
||||
static const int HEADER_AREA_SIZE = ROUND_UP(sizeof(Header), 32) + 40;
|
||||
|
||||
/* SymbolBlock */
|
||||
|
||||
// [R89JEL]:/bin/RVL/Debug/mainD.elf:.debug::0x24881
|
||||
@@ -332,9 +334,17 @@ namespace nw4r { namespace snd { namespace detail
|
||||
|
||||
u32 ConvertLabelStringToId(SoundArchiveFile::StringTree const *tree,
|
||||
char const *str) const;
|
||||
u32 ConvertLabelStringToSoundId(char const *label) const
|
||||
{
|
||||
return ConvertLabelStringToId(mStringTreeSound, label);
|
||||
const char* GetSoundLabelString(u32 id) const;
|
||||
u32 GetSoundUserParam(u32 id) const;
|
||||
|
||||
u32 ConvertLabelStringToSoundId(const char* pLabel) const {
|
||||
return ConvertLabelStringToId(mStringTreeSound, pLabel);
|
||||
}
|
||||
u32 ConvertLabelStringToPlayerId(const char* pLabel) const {
|
||||
return ConvertLabelStringToId(mStringTreePlayer, pLabel);
|
||||
}
|
||||
u32 ConvertLabelStringToGroupId(const char* pLabel) const {
|
||||
return ConvertLabelStringToId(mStringTreeGroup, pLabel);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -184,7 +184,9 @@ namespace nw4r { namespace snd
|
||||
u32 GetRequiredMemSize(SoundArchive const *arc);
|
||||
u32 GetRequiredStrmBufferSize(SoundArchive const *arc);
|
||||
void const *GetGroupAddress(u32 groupId) const;
|
||||
void SetGroupAddress(u32 id, const void* pAddr);
|
||||
void const *GetGroupWaveDataAddress(u32 groupId) const;
|
||||
void SetGroupWaveDataAddress(u32 id, const void* pAddr);
|
||||
void const *GetFileAddress(u32 fileId) const;
|
||||
void const *GetFileWaveDataAddress(u32 fileId) const;
|
||||
void const *detail_GetFileAddress(u32 fileId) const;
|
||||
|
||||
@@ -27,6 +27,7 @@ namespace nw4r { namespace snd
|
||||
~SoundHandle() { DetachSound(); }
|
||||
|
||||
// methods
|
||||
void detail_AttachSoundAsTempHandle(detail::BasicSound* pSound);
|
||||
void detail_AttachSound(detail::BasicSound *sound);
|
||||
bool IsAttachedSound() const { return mSound != nullptr; }
|
||||
detail::BasicSound *detail_GetAttachedSound() { return mSound; }
|
||||
|
||||
@@ -42,6 +42,17 @@ namespace nw4r { namespace snd { namespace detail
|
||||
CALLBACK_STATUS_DROP_DSP,
|
||||
};
|
||||
|
||||
enum VoiceSyncFlag {
|
||||
SYNC_AX_SRC_INITIAL = (1 << 0),
|
||||
SYNC_AX_VOICE = (1 << 1),
|
||||
SYNC_AX_SRC = (1 << 2),
|
||||
SYNC_AX_VE = (1 << 3),
|
||||
SYNC_AX_MIX = (1 << 4),
|
||||
SYNC_AX_LPF = (1 << 5),
|
||||
SYNC_AX_REMOTE = (1 << 7),
|
||||
SYNC_AX_BIQUAD = (1 << 8),
|
||||
};
|
||||
|
||||
// typedefs
|
||||
public:
|
||||
typedef ut::LinkList<Voice, 0xec> LinkList;
|
||||
|
||||
@@ -18,6 +18,9 @@ namespace nw4r { namespace snd { namespace detail
|
||||
// [R89JEL]:/bin/RVL/Debug/mainD.elf:.debug::0x2ffb36
|
||||
class VoiceManager
|
||||
{
|
||||
public:
|
||||
static const int VOICE_MAX = AX_VOICE_MAX;
|
||||
static const int WORK_SIZE_MAX = VOICE_MAX * sizeof(Voice);
|
||||
// methods
|
||||
public:
|
||||
// instance accessors
|
||||
|
||||
@@ -17,6 +17,27 @@ extern "C" {
|
||||
#define AX_SAMPLES_PER_FRAME_RMT 18
|
||||
#define AX_FRAME_SIZE (AX_SAMPLES_PER_FRAME * AX_SAMPLE_DEPTH_BYTES)
|
||||
|
||||
/**
|
||||
* Stereo: Left, Right, Surround
|
||||
* DPL2: Left, Right, Left Surround, Right Surround
|
||||
*/
|
||||
typedef enum {
|
||||
AX_STEREO_L,
|
||||
AX_STEREO_R,
|
||||
AX_STEREO_S,
|
||||
|
||||
AX_STEREO_MAX
|
||||
} AXStereoChannel;
|
||||
|
||||
typedef enum {
|
||||
AX_DPL2_L,
|
||||
AX_DPL2_R,
|
||||
AX_DPL2_LS,
|
||||
AX_DPL2_RS,
|
||||
|
||||
AX_DPL2_MAX
|
||||
} AXDPL2Channel;
|
||||
|
||||
typedef void (*AXAuxCallback)(void *chans, void *context);
|
||||
|
||||
void __AXAuxInit(void);
|
||||
|
||||
@@ -32,8 +32,8 @@ enum WPADResult_et {
|
||||
WPAD_ERR_OK = 0,
|
||||
|
||||
WPAD_ERR_NO_CONTROLLER = -1, /* name known from asserts */
|
||||
WPAD_ERR_COMMUNICATION_ERROR = -2, // [RT3P54] has this as WPAD_ERR_BUSY
|
||||
WPAD_ERR_3 = -3, // [RT3P54] has this as WPAD_ERR_TRANSFER
|
||||
WPAD_ERR_BUSY = -2, // [RT3P54] has this as WPAD_ERR_BUSY
|
||||
WPAD_ERR_TRANSFER = -3, // [RT3P54] has this as WPAD_ERR_TRANSFER
|
||||
WPAD_ERR_INVALID = -4, /* name comes from [R89JEL] */
|
||||
// WPAD_ERR_5 = -5, /* unknown */
|
||||
// WPAD_ERR_6 = -6, /* unknown */
|
||||
@@ -260,8 +260,8 @@ enum WPADMotorCommand_et {
|
||||
// WPADControlSpeaker
|
||||
typedef u32 WPADSpeakerCommand;
|
||||
enum WPADSpeakerCommand_et {
|
||||
WPAD_SPEAKER_DISABLE = 0,
|
||||
WPAD_SPEAKER_ENABLE = 1, // might be ON? see HBMRemoteSpk.cpp
|
||||
WPAD_SPEAKER_OFF = 0,
|
||||
WPAD_SPEAKER_ON = 1, // might be ON? see HBMRemoteSpk.cpp
|
||||
WPAD_SPEAKER_MUTE = 2,
|
||||
WPAD_SPEAKER_UNMUTE = 3,
|
||||
WPAD_SPEAKER_PLAY = 4, // figured out from HBM usage
|
||||
|
||||
@@ -8,6 +8,9 @@ inline size_t strlen(const char *str) {
|
||||
return ::strlen(str);
|
||||
}
|
||||
|
||||
using ::strncpy;
|
||||
using ::strncat;
|
||||
|
||||
inline char *strcpy(char *dest, const char *src) {
|
||||
return ::strcpy(dest, src);
|
||||
}
|
||||
|
||||
@@ -306,6 +306,14 @@ OutputMode AxManager::GetOutputMode()
|
||||
return mOutputMode;
|
||||
}
|
||||
|
||||
void AxManager::SetMasterVolume(f32 volume, int frame) {
|
||||
mMasterVolume.SetTarget(ut::Clamp(volume, 0.0f, 1.0f), (frame + 2) / 3);
|
||||
|
||||
if (frame == 0) {
|
||||
VoiceManager::GetInstance().UpdateAllVoicesSync(Voice::SYNC_AX_VE);
|
||||
}
|
||||
}
|
||||
|
||||
void AxManager::SetMainOutVolume(f32 volume, int frames)
|
||||
{
|
||||
volume = ut::Clamp(volume, 0.0f, 1.0f);
|
||||
@@ -326,6 +334,73 @@ void AxManager::AxCallbackFunc()
|
||||
(*GetInstance().mNextAxRegisterCallback)();
|
||||
}
|
||||
|
||||
bool AxManager::AppendEffect(AuxBus bus, FxBase* pFx) {
|
||||
if (!mAuxFadeVolume[bus].IsFinished()) {
|
||||
ShutdownEffect(bus);
|
||||
}
|
||||
|
||||
mAuxFadeVolume[bus].SetTarget(1.0f, 0);
|
||||
|
||||
switch (bus) {
|
||||
case AUX_A: {
|
||||
AXSetAuxAReturnVolume(AX_MAX_VOLUME);
|
||||
break;
|
||||
}
|
||||
|
||||
case AUX_B: {
|
||||
AXSetAuxBReturnVolume(AX_MAX_VOLUME);
|
||||
break;
|
||||
}
|
||||
|
||||
case AUX_C: {
|
||||
AXSetAuxCReturnVolume(AX_MAX_VOLUME);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!pFx->StartUp()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ut::AutoInterruptLock lock;
|
||||
|
||||
if (GetEffectList(bus).IsEmpty()) {
|
||||
switch (bus) {
|
||||
case AUX_A: {
|
||||
AXRegisterAuxACallback(AuxCallbackFunc,
|
||||
reinterpret_cast<void*>(bus));
|
||||
break;
|
||||
}
|
||||
|
||||
case AUX_B: {
|
||||
AXRegisterAuxBCallback(AuxCallbackFunc,
|
||||
reinterpret_cast<void*>(bus));
|
||||
break;
|
||||
}
|
||||
|
||||
case AUX_C: {
|
||||
AXRegisterAuxCCallback(AuxCallbackFunc,
|
||||
reinterpret_cast<void*>(bus));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mAuxCallbackWaitCounter[bus] = 2;
|
||||
}
|
||||
|
||||
GetEffectList(bus).PushBack(pFx);
|
||||
return true;
|
||||
}
|
||||
|
||||
void AxManager::ClearEffect(AuxBus bus, int frame) {
|
||||
if (frame == 0) {
|
||||
ShutdownEffect(bus);
|
||||
return;
|
||||
}
|
||||
|
||||
mAuxFadeVolume[bus].SetTarget(0.0f, (frame + 2) / 3);
|
||||
}
|
||||
|
||||
void AxManager::ShutdownEffect(AuxBus bus)
|
||||
{
|
||||
ut::AutoInterruptLock lock;
|
||||
@@ -365,4 +440,77 @@ void AxManager::SetBiquadFilterCallback(int type,
|
||||
sBiquadFilterCallbackTable[type] = biquad;
|
||||
}
|
||||
|
||||
void AxManager::AuxCallbackFunc(void* pChans, void* pContext) {
|
||||
int num;
|
||||
void* buffer[AX_DPL2_MAX];
|
||||
|
||||
void** ppChans = static_cast<void**>(pChans);
|
||||
AuxBus bus = static_cast<AuxBus>(reinterpret_cast<u32>(pContext));
|
||||
|
||||
if (GetInstance().GetOutputMode() == OUTPUT_MODE_DPL2) {
|
||||
num = AX_DPL2_MAX;
|
||||
|
||||
buffer[AX_DPL2_L] = ppChans[AX_DPL2_L];
|
||||
buffer[AX_DPL2_R] = ppChans[AX_DPL2_R];
|
||||
buffer[AX_DPL2_LS] = ppChans[AX_DPL2_LS];
|
||||
buffer[AX_DPL2_RS] = ppChans[AX_DPL2_RS];
|
||||
} else {
|
||||
num = AX_STEREO_MAX;
|
||||
|
||||
buffer[AX_STEREO_L] = ppChans[AX_STEREO_L];
|
||||
buffer[AX_STEREO_R] = ppChans[AX_STEREO_R];
|
||||
buffer[AX_STEREO_S] = ppChans[AX_STEREO_S];
|
||||
}
|
||||
|
||||
if (GetInstance().mAuxCallbackWaitCounter[bus] > 0) {
|
||||
GetInstance().mAuxCallbackWaitCounter[bus]--;
|
||||
|
||||
for (int i = 0; i < num; i++) {
|
||||
std::memset(buffer[i], 0, FX_BUFFER_SIZE);
|
||||
}
|
||||
} else if (GetInstance().GetEffectList(bus).IsEmpty()) {
|
||||
for (int i = 0; i < num; i++) {
|
||||
std::memset(buffer[i], 0, FX_BUFFER_SIZE);
|
||||
}
|
||||
} else {
|
||||
for (FxBase::LinkList::Iterator it =
|
||||
GetInstance().GetEffectList(bus).GetBeginIter();
|
||||
it != GetInstance().GetEffectList(bus).GetEndIter(); ++it) {
|
||||
|
||||
it->UpdateBuffer(num, buffer, FX_BUFFER_SIZE, FX_SAMPLE_FORMAT,
|
||||
FX_SAMPLE_RATE, GetInstance().GetOutputMode());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AxManager::PrepareReset() {
|
||||
if (mOldAidCallback != NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
mVolumeForReset.SetTarget(0.0f, 3);
|
||||
mResetReadyCounter = -1;
|
||||
mOldAidCallback = AIRegisterDMACallback(AiDmaCallbackFunc);
|
||||
}
|
||||
|
||||
void AxManager::AiDmaCallbackFunc() {
|
||||
static bool finishedFlag = false;
|
||||
|
||||
AxManager& r = GetInstance();
|
||||
r.mOldAidCallback();
|
||||
|
||||
if (finishedFlag) {
|
||||
if (r.mResetReadyCounter < 0) {
|
||||
AXSetMaxDspCycles(0);
|
||||
r.mResetReadyCounter = AUX_CALLBACK_WAIT_FRAME;
|
||||
}
|
||||
} else if (r.mVolumeForReset.GetValue() == 0.0f) {
|
||||
finishedFlag = true;
|
||||
}
|
||||
|
||||
if (r.mResetReadyCounter > 0) {
|
||||
r.mResetReadyCounter--;
|
||||
}
|
||||
}
|
||||
|
||||
}}} // namespace nw4r::snd::detail
|
||||
|
||||
@@ -1 +1,57 @@
|
||||
#include "nw4r/snd/snd_AxfxImpl.h"
|
||||
|
||||
#include "nw4r/ut/ut_algorithm.h"
|
||||
|
||||
namespace nw4r {
|
||||
namespace snd {
|
||||
namespace detail {
|
||||
|
||||
AxfxImpl* AxfxImpl::mCurrentFx = NULL;
|
||||
u32 AxfxImpl::mAllocatedSize = 0;
|
||||
|
||||
bool AxfxImpl::CreateHeap(void* pBuffer, u32 size) {
|
||||
mHeap = MEMCreateFrmHeap(pBuffer, size);
|
||||
return mHeap != NULL;
|
||||
}
|
||||
|
||||
void AxfxImpl::DestroyHeap() {
|
||||
if (mHeap != NULL) {
|
||||
MEMDestroyFrmHeap(mHeap);
|
||||
}
|
||||
}
|
||||
|
||||
void AxfxImpl::HookAlloc(AXFXAllocHook* pAllocHook, AXFXFreeHook* pFreeHook) {
|
||||
AXFXGetHooks(pAllocHook, pFreeHook);
|
||||
AXFXSetHooks(Alloc, Free);
|
||||
mCurrentFx = this;
|
||||
}
|
||||
|
||||
void AxfxImpl::RestoreAlloc(AXFXAllocHook allocHook, AXFXFreeHook freeHook) {
|
||||
AXFXSetHooks(allocHook, freeHook);
|
||||
mCurrentFx = NULL;
|
||||
}
|
||||
|
||||
void* AxfxImpl::Alloc(u32 size) {
|
||||
void* pBlock = MEMAllocFromFrmHeap(mCurrentFx->mHeap, size);
|
||||
|
||||
mCurrentFx->mAllocCount++;
|
||||
mAllocatedSize += ut::RoundUp(size, 4);
|
||||
|
||||
return pBlock;
|
||||
}
|
||||
|
||||
void AxfxImpl::Free(void* pBlock) {
|
||||
#pragma unused(pBlock)
|
||||
|
||||
if (mCurrentFx->mAllocCount != 0) {
|
||||
mCurrentFx->mAllocCount--;
|
||||
}
|
||||
|
||||
if (mCurrentFx->mAllocCount == 0) {
|
||||
MEMFreeToFrmHeap(mCurrentFx->mHeap, MEM_FRM_HEAP_FREE_ALL);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace snd
|
||||
} // namespace nw4r
|
||||
|
||||
@@ -1,6 +1,235 @@
|
||||
/* Only implemented to the extent necessary to match data sections. */
|
||||
|
||||
#include "nw4r/snd/snd_DvdSoundArchive.h"
|
||||
#include "nw4r/ut/ut_DvdLockedFileStream.h"
|
||||
#include <cstring>
|
||||
#include <new>
|
||||
|
||||
nw4r::snd::DvdSoundArchive::DvdSoundArchive() {}
|
||||
nw4r::snd::DvdSoundArchive::DvdFileStream::DvdFileStream() {}
|
||||
namespace nw4r {
|
||||
namespace snd {
|
||||
|
||||
class DvdSoundArchive::DvdFileStream : public ut::DvdLockedFileStream {
|
||||
public:
|
||||
DvdFileStream(const DVDFileInfo* pFileInfo, u32 offset, u32 size);
|
||||
DvdFileStream(s32 entrynum, u32 offset, u32 size);
|
||||
|
||||
virtual s32 Read(void* pDst, u32 size); // at 0x14
|
||||
virtual void Seek(s32 offset, u32 origin); // at 0x44
|
||||
|
||||
virtual u32 Tell() const {
|
||||
return ut::DvdFileStream::Tell() - mOffset;
|
||||
} // at 0x58
|
||||
|
||||
virtual u32 GetSize() const {
|
||||
return mSize;
|
||||
} // at 0x40
|
||||
|
||||
private:
|
||||
s32 mOffset; // at 0x70
|
||||
s32 mSize; // at 0x74
|
||||
};
|
||||
|
||||
DvdSoundArchive::DvdSoundArchive() : mOpen(false) {}
|
||||
|
||||
DvdSoundArchive::~DvdSoundArchive() {
|
||||
Close();
|
||||
}
|
||||
|
||||
bool DvdSoundArchive::Open(s32 entrynum) {
|
||||
if (!DVDFastOpen(entrynum, &mFileInfo)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mOpen = true;
|
||||
return LoadFileHeader();
|
||||
}
|
||||
|
||||
bool DvdSoundArchive::Open(const char* pPath) {
|
||||
s32 entrynum = DVDConvertPathToEntrynum(pPath);
|
||||
if (entrynum < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Open(entrynum)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
char extRoot[FILE_PATH_MAX];
|
||||
for (int i = std::strlen(pPath) - 1; i >= 0; i--) {
|
||||
if (pPath[i] == '/' || pPath[i] == '\\') {
|
||||
// @bug Long path can overflow extRoot buffer
|
||||
std::strncpy(extRoot, pPath, i);
|
||||
extRoot[i] = '\0';
|
||||
|
||||
SetExternalFileRoot(extRoot);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DvdSoundArchive::Close() {
|
||||
DVDClose(&mFileInfo);
|
||||
mOpen = false;
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
ut::FileStream* DvdSoundArchive::OpenStream(void* pBuffer, int size, u32 offset,
|
||||
u32 length) const {
|
||||
if (!mOpen) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (size < sizeof(DvdFileStream)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return new (pBuffer) DvdFileStream(&mFileInfo, offset, length);
|
||||
}
|
||||
|
||||
ut::FileStream* DvdSoundArchive::OpenExtStream(void* pBuffer, int size,
|
||||
const char* pExtPath, u32 offset,
|
||||
u32 length) const {
|
||||
if (!mOpen) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (size < sizeof(DvdFileStream)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
s32 entrynum = DVDConvertPathToEntrynum(pExtPath);
|
||||
if (entrynum < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return new (pBuffer) DvdFileStream(entrynum, offset, length);
|
||||
}
|
||||
|
||||
int DvdSoundArchive::detail_GetRequiredStreamBufferSize() const {
|
||||
return sizeof(DvdFileStream);
|
||||
}
|
||||
|
||||
bool DvdSoundArchive::LoadFileHeader() {
|
||||
u8 headerArea[detail::SoundArchiveFile::HEADER_AREA_SIZE];
|
||||
|
||||
static const u32 headerAlignSize =
|
||||
ut::RoundUp(sizeof(detail::SoundArchiveFile::Header), 32);
|
||||
|
||||
void* pFile = ut::RoundUp<u8>(headerArea, 32);
|
||||
|
||||
s32 bytesRead =
|
||||
DVDReadPrio(&mFileInfo, pFile, headerAlignSize, 0, DVD_PRIO_MEDIUM);
|
||||
|
||||
if (bytesRead != headerAlignSize) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mFileReader.Init(pFile);
|
||||
Setup(&mFileReader);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DvdSoundArchive::LoadHeader(void* pBuffer, u32 size) {
|
||||
u32 infoSize = mFileReader.GetInfoChunkSize();
|
||||
s32 infoOffset = mFileReader.GetInfoChunkOffset();
|
||||
|
||||
if (size < infoSize) {
|
||||
return false;
|
||||
}
|
||||
|
||||
s32 bytesRead =
|
||||
DVDReadPrio(&mFileInfo, pBuffer, infoSize, infoOffset, DVD_PRIO_MEDIUM);
|
||||
|
||||
if (bytesRead != infoSize) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mFileReader.SetInfoChunk(pBuffer, infoSize);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DvdSoundArchive::LoadLabelStringData(void* pBuffer, u32 size) {
|
||||
u32 labelSize = mFileReader.GetLabelStringChunkSize();
|
||||
s32 labelOffset = mFileReader.GetLabelStringChunkOffset();
|
||||
|
||||
if (size < labelSize) {
|
||||
return false;
|
||||
}
|
||||
|
||||
s32 bytesRead = DVDReadPrio(&mFileInfo, pBuffer, labelSize, labelOffset,
|
||||
DVD_PRIO_MEDIUM);
|
||||
|
||||
if (bytesRead != labelSize) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mFileReader.SetStringChunk(pBuffer, labelSize);
|
||||
return true;
|
||||
}
|
||||
|
||||
DvdSoundArchive::DvdFileStream::DvdFileStream(const DVDFileInfo* pFileInfo,
|
||||
u32 offset, u32 size)
|
||||
: DvdLockedFileStream(pFileInfo, false), mOffset(offset), mSize(size) {
|
||||
if (mSize == 0) {
|
||||
mSize = ut::DvdFileStream::GetSize();
|
||||
}
|
||||
|
||||
ut::DvdFileStream::Seek(mOffset, SEEKORG_BEG);
|
||||
}
|
||||
|
||||
DvdSoundArchive::DvdFileStream::DvdFileStream(s32 entrynum, u32 offset,
|
||||
u32 size)
|
||||
: DvdLockedFileStream(entrynum), mOffset(offset), mSize(size) {
|
||||
if (mSize == 0) {
|
||||
mSize = ut::DvdFileStream::GetSize();
|
||||
}
|
||||
|
||||
ut::DvdFileStream::Seek(mOffset, SEEKORG_BEG);
|
||||
}
|
||||
|
||||
s32 DvdSoundArchive::DvdFileStream::Read(void* pDst, u32 size) {
|
||||
u32 endOffset = mOffset + mSize;
|
||||
u32 startOffset = ut::DvdFileStream::Tell();
|
||||
|
||||
if (startOffset + size > endOffset) {
|
||||
size = ut::RoundUp(endOffset - ut::DvdFileStream::Tell(), 32);
|
||||
}
|
||||
|
||||
return DvdLockedFileStream::Read(pDst, size);
|
||||
}
|
||||
|
||||
void DvdSoundArchive::DvdFileStream::Seek(s32 offset, u32 origin) {
|
||||
switch (origin) {
|
||||
case SEEKORG_BEG: {
|
||||
offset += mOffset;
|
||||
break;
|
||||
}
|
||||
|
||||
case SEEKORG_CUR: {
|
||||
offset += ut::DvdFileStream::Tell();
|
||||
break;
|
||||
}
|
||||
|
||||
case SEEKORG_END: {
|
||||
offset = mOffset + mSize - offset;
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (offset < mOffset) {
|
||||
offset = mOffset;
|
||||
} else if (offset > mOffset + mSize) {
|
||||
offset = mOffset + mSize;
|
||||
}
|
||||
|
||||
ut::DvdFileStream::Seek(offset, SEEKORG_BEG);
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "nw4r/snd/snd_SoundThread.h"
|
||||
|
||||
#include "nw4r/NW4RAssert.hpp"
|
||||
#include "nw4r/snd/snd_global.h"
|
||||
|
||||
/*******************************************************************************
|
||||
* types
|
||||
@@ -30,6 +31,17 @@ namespace nw4r { namespace ut { struct LinkListNode; }}
|
||||
|
||||
namespace nw4r { namespace snd { namespace detail {
|
||||
|
||||
ExternalSoundPlayer::ExternalSoundPlayer() : mPlayableCount(1) {}
|
||||
|
||||
ExternalSoundPlayer::~ExternalSoundPlayer() {
|
||||
NW4R_RANGE_FOR_NO_AUTO_INC(it, mSoundList)
|
||||
{
|
||||
decltype(it) curItr = it++;
|
||||
|
||||
curItr->DetachExternalSoundPlayer(this);
|
||||
}
|
||||
}
|
||||
|
||||
// not sure which one uses this exactly, maybe StopAllSound?
|
||||
DECOMP_FORCE_CLASS_METHOD(
|
||||
BasicSound::ExtSoundPlayerPlayLinkList,
|
||||
@@ -64,6 +76,14 @@ bool ExternalSoundPlayer::AppendSound(BasicSound *sound)
|
||||
return true;
|
||||
}
|
||||
|
||||
void ExternalSoundPlayer::SetPlayableSoundCount(int count) {
|
||||
mPlayableCount = count;
|
||||
|
||||
while (GetPlayingSoundCount() > GetPlayableSoundCount()) {
|
||||
GetLowestPrioritySound()->Shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
void ExternalSoundPlayer::RemoveSound(BasicSound *sound)
|
||||
{
|
||||
mSoundList.Erase(sound);
|
||||
|
||||
@@ -1 +1,136 @@
|
||||
#include "nw4r/snd/snd_FrameHeap.h"
|
||||
#include <new>
|
||||
|
||||
namespace nw4r {
|
||||
namespace snd {
|
||||
namespace detail {
|
||||
|
||||
FrameHeap::FrameHeap() : mHandle(NULL) {}
|
||||
|
||||
FrameHeap::~FrameHeap() {
|
||||
if (IsValid()) {
|
||||
Destroy();
|
||||
}
|
||||
}
|
||||
|
||||
bool FrameHeap::Create(void* pBase, u32 size) {
|
||||
if (IsValid()) {
|
||||
Destroy();
|
||||
}
|
||||
|
||||
void* pEnd = static_cast<u8*>(pBase) + size;
|
||||
pBase = ut::RoundUp(pBase, 4);
|
||||
if (pBase > pEnd) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mHandle = MEMCreateFrmHeap(pBase, ut::GetOffsetFromPtr(pBase, pEnd));
|
||||
if (mHandle == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!NewSection()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void FrameHeap::Destroy() {
|
||||
if (!IsValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
ClearSection();
|
||||
MEMFreeToFrmHeap(mHandle, MEM_FRM_HEAP_FREE_ALL);
|
||||
|
||||
MEMDestroyFrmHeap(mHandle);
|
||||
mHandle = NULL;
|
||||
}
|
||||
|
||||
void FrameHeap::Clear() {
|
||||
ClearSection();
|
||||
MEMFreeToFrmHeap(mHandle, MEM_FRM_HEAP_FREE_ALL);
|
||||
|
||||
NewSection();
|
||||
}
|
||||
|
||||
void* FrameHeap::Alloc(u32 size, FreeCallback pCallback, void* pCallbackArg) {
|
||||
void* pBuffer = MEMAllocFromFrmHeapEx(
|
||||
mHandle, BLOCK_BUFFER_SIZE + ut::RoundUp(size, HEAP_ALIGN), HEAP_ALIGN);
|
||||
|
||||
if (pBuffer == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Block* pBlock = new (pBuffer) Block(size, pCallback, pCallbackArg);
|
||||
mSectionList.GetBack().AppendBlock(pBlock);
|
||||
|
||||
return pBlock->GetBufferAddr();
|
||||
}
|
||||
|
||||
int FrameHeap::SaveState() {
|
||||
if (!MEMRecordStateForFrmHeap(mHandle, mSectionList.GetSize())) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!NewSection()) {
|
||||
MEMFreeByStateToFrmHeap(mHandle, 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return GetCurrentLevel();
|
||||
}
|
||||
|
||||
void FrameHeap::LoadState(int id) {
|
||||
if (id == 0) {
|
||||
Clear();
|
||||
return;
|
||||
}
|
||||
|
||||
while (id < static_cast<int>(mSectionList.GetSize())) {
|
||||
Section& rSection = mSectionList.GetBack();
|
||||
rSection.~Section();
|
||||
mSectionList.Erase(&rSection);
|
||||
}
|
||||
|
||||
MEMFreeByStateToFrmHeap(mHandle, id);
|
||||
MEMRecordStateForFrmHeap(mHandle, mSectionList.GetSize());
|
||||
|
||||
NewSection();
|
||||
}
|
||||
|
||||
int FrameHeap::GetCurrentLevel() const {
|
||||
return mSectionList.GetSize() - 1;
|
||||
}
|
||||
|
||||
u32 FrameHeap::GetFreeSize() const {
|
||||
u32 freeSize = MEMGetAllocatableSizeForFrmHeapEx(mHandle, HEAP_ALIGN);
|
||||
if (freeSize < BLOCK_BUFFER_SIZE) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ut::RoundDown(freeSize - BLOCK_BUFFER_SIZE, HEAP_ALIGN);
|
||||
}
|
||||
|
||||
bool FrameHeap::NewSection() {
|
||||
void* pSection = MEMAllocFromFrmHeap(mHandle, sizeof(Section));
|
||||
if (pSection == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mSectionList.PushBack(new (pSection) Section());
|
||||
return true;
|
||||
}
|
||||
|
||||
void FrameHeap::ClearSection() {
|
||||
while (!mSectionList.IsEmpty()) {
|
||||
Section& rSection = mSectionList.GetBack();
|
||||
rSection.~Section();
|
||||
mSectionList.Erase(&rSection);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace snd
|
||||
} // namespace nw4r
|
||||
|
||||
@@ -1 +1,264 @@
|
||||
#include "nw4r/snd/snd_NandSoundArchive.h"
|
||||
#include <cstring>
|
||||
#include <new>
|
||||
|
||||
namespace nw4r {
|
||||
namespace snd {
|
||||
|
||||
class NandSoundArchive::NandFileStream : public ut::NandFileStream {
|
||||
public:
|
||||
NandFileStream(const NANDFileInfo* pFileInfo, u32 offset, u32 size);
|
||||
NandFileStream(const char* pPath, u32 offset, u32 size);
|
||||
|
||||
virtual s32 Read(void* pDst, u32 size); // at 0x14
|
||||
virtual void Seek(s32 offset, u32 origin); // at 0x44
|
||||
|
||||
virtual u32 Tell() const {
|
||||
return ut::NandFileStream::Tell() - mOffset;
|
||||
} // at 0x58
|
||||
|
||||
virtual u32 GetSize() const {
|
||||
return mSize;
|
||||
} // at 0x40
|
||||
|
||||
private:
|
||||
s32 mOffset; // at 0x16C
|
||||
s32 mSize; // at 0x170
|
||||
};
|
||||
|
||||
NandSoundArchive::NandSoundArchive() : mOpen(false) {}
|
||||
|
||||
NandSoundArchive::~NandSoundArchive() {
|
||||
Close();
|
||||
}
|
||||
|
||||
bool NandSoundArchive::Open(const char* pPath) {
|
||||
if (mOpen) {
|
||||
Close();
|
||||
}
|
||||
|
||||
if (NANDOpen(pPath, &mFileInfo, NAND_ACCESS_READ)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mOpen = true;
|
||||
|
||||
if (!LoadFileHeader()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
char currentDir[64];
|
||||
NANDGetCurrentDir(currentDir);
|
||||
u32 currDirLen = std::strlen(currentDir);
|
||||
|
||||
char extRoot[FILE_PATH_MAX];
|
||||
std::strncpy(extRoot, currentDir, currDirLen + 1);
|
||||
|
||||
for (int i = std::strlen(pPath) - 1; i >= 0; i--) {
|
||||
if (pPath[i] == '/' || pPath[i] == '\\') {
|
||||
// @bug Long path can overflow extRoot buffer
|
||||
std::strncat(extRoot, pPath, i);
|
||||
extRoot[currDirLen + i] = '\0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
SetExternalFileRoot(extRoot);
|
||||
return true;
|
||||
}
|
||||
|
||||
void NandSoundArchive::Close() {
|
||||
if (mOpen) {
|
||||
NANDClose(&mFileInfo);
|
||||
mOpen = false;
|
||||
}
|
||||
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
ut::FileStream* NandSoundArchive::OpenStream(void* pBuffer, int size,
|
||||
u32 offset, u32 length) const {
|
||||
if (!mOpen) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (size < sizeof(NandFileStream)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return new (pBuffer) NandFileStream(&mFileInfo, offset, length);
|
||||
}
|
||||
|
||||
ut::FileStream* NandSoundArchive::OpenExtStream(void* pBuffer, int size,
|
||||
const char* pExtPath,
|
||||
u32 offset, u32 length) const {
|
||||
if (!mOpen) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (size < sizeof(NandFileStream)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
NandFileStream* pExtStream =
|
||||
new (pBuffer) NandFileStream(pExtPath, offset, length);
|
||||
|
||||
if (!pExtStream->IsAvailable()) {
|
||||
pExtStream->~NandFileStream();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return pExtStream;
|
||||
}
|
||||
|
||||
int NandSoundArchive::detail_GetRequiredStreamBufferSize() const {
|
||||
return sizeof(NandFileStream);
|
||||
}
|
||||
|
||||
bool NandSoundArchive::LoadFileHeader() {
|
||||
u8 headerArea[detail::SoundArchiveFile::HEADER_AREA_SIZE];
|
||||
|
||||
static const u32 headerAlignSize =
|
||||
ut::RoundUp(sizeof(detail::SoundArchiveFile::Header), 32);
|
||||
|
||||
void* pFile = ut::RoundUp<u8>(headerArea, 32);
|
||||
|
||||
if (NANDSeek(&mFileInfo, 0, NAND_SEEK_BEG) != NAND_RESULT_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
s32 bytesRead = NANDRead(&mFileInfo, pFile, headerAlignSize);
|
||||
if (bytesRead != headerAlignSize) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mFileReader.Init(pFile);
|
||||
Setup(&mFileReader);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NandSoundArchive::LoadHeader(void* pBuffer, u32 size) {
|
||||
u32 infoSize = mFileReader.GetInfoChunkSize();
|
||||
|
||||
u32 infoOffsetU = mFileReader.GetInfoChunkOffset();
|
||||
s32 infoOffset = *reinterpret_cast<s32*>(&infoOffsetU);
|
||||
|
||||
if (size < infoSize) {
|
||||
return false;
|
||||
}
|
||||
|
||||
s32 currOffset = NANDSeek(&mFileInfo, infoOffset, NAND_SEEK_BEG);
|
||||
if (currOffset != infoOffset) {
|
||||
return false;
|
||||
}
|
||||
|
||||
s32 bytesRead = NANDRead(&mFileInfo, pBuffer, infoSize);
|
||||
if (bytesRead != infoSize) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mFileReader.SetInfoChunk(pBuffer, infoSize);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NandSoundArchive::LoadLabelStringData(void* pBuffer, u32 size) {
|
||||
u32 labelSize = mFileReader.GetLabelStringChunkSize();
|
||||
|
||||
u32 labelOffsetU = mFileReader.GetLabelStringChunkOffset();
|
||||
s32 labelOffset = *reinterpret_cast<s32*>(&labelOffsetU);
|
||||
|
||||
if (size < labelSize) {
|
||||
return false;
|
||||
}
|
||||
|
||||
s32 currOffset = NANDSeek(&mFileInfo, labelOffset, NAND_SEEK_BEG);
|
||||
if (currOffset != labelOffset) {
|
||||
return false;
|
||||
}
|
||||
|
||||
s32 bytesRead = NANDRead(&mFileInfo, pBuffer, labelSize);
|
||||
if (bytesRead != labelSize) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mFileReader.SetStringChunk(pBuffer, labelSize);
|
||||
return true;
|
||||
}
|
||||
|
||||
NandSoundArchive::NandFileStream::NandFileStream(const NANDFileInfo* pFileInfo,
|
||||
u32 offset, u32 size)
|
||||
: ut::NandFileStream(pFileInfo, NAND_ACCESS_READ, false),
|
||||
mOffset(offset),
|
||||
mSize(size) {
|
||||
|
||||
if (IsAvailable()) {
|
||||
if (mSize == 0) {
|
||||
mSize = ut::NandFileStream::GetSize();
|
||||
}
|
||||
|
||||
ut::NandFileStream::Seek(mOffset, SEEKORG_BEG);
|
||||
}
|
||||
}
|
||||
|
||||
NandSoundArchive::NandFileStream::NandFileStream(const char* pPath, u32 offset,
|
||||
u32 size)
|
||||
: ut::NandFileStream(pPath, NAND_ACCESS_READ),
|
||||
mOffset(offset),
|
||||
mSize(size) {
|
||||
|
||||
if (IsAvailable()) {
|
||||
if (mSize == 0) {
|
||||
mSize = ut::NandFileStream::GetSize();
|
||||
}
|
||||
|
||||
ut::NandFileStream::Seek(mOffset, SEEKORG_BEG);
|
||||
}
|
||||
}
|
||||
|
||||
s32 NandSoundArchive::NandFileStream::Read(void* pDst, u32 size) {
|
||||
u32 endOffset = mOffset + mSize;
|
||||
u32 startOffset = ut::NandFileStream::Tell();
|
||||
|
||||
if (startOffset + size > endOffset) {
|
||||
size = ut::RoundUp(endOffset - ut::NandFileStream::Tell(), 32);
|
||||
}
|
||||
|
||||
s32 bytesRead = ut::NandFileStream::Read(pDst, size);
|
||||
DCStoreRange(pDst, size);
|
||||
|
||||
return bytesRead;
|
||||
}
|
||||
|
||||
void NandSoundArchive::NandFileStream::Seek(s32 offset, u32 origin) {
|
||||
switch (origin) {
|
||||
case SEEKORG_BEG: {
|
||||
offset += mOffset;
|
||||
break;
|
||||
}
|
||||
|
||||
case SEEKORG_CUR: {
|
||||
offset += ut::NandFileStream::Tell();
|
||||
break;
|
||||
}
|
||||
|
||||
case SEEKORG_END: {
|
||||
offset = mOffset + mSize - offset;
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (offset < mOffset) {
|
||||
offset = mOffset;
|
||||
} else if (offset > mOffset + mSize) {
|
||||
offset = mOffset + mSize;
|
||||
}
|
||||
|
||||
ut::NandFileStream::Seek(offset, SEEKORG_BEG);
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
@@ -1 +1,379 @@
|
||||
#include "nw4r/snd/snd_RemoteSpeaker.h"
|
||||
#include "common.h"
|
||||
#include "nw4r/snd/snd_RemoteSpeakerManager.h"
|
||||
#include "nw4r/ut/ut_Lock.h"
|
||||
#include <cstring>
|
||||
|
||||
namespace nw4r {
|
||||
namespace snd {
|
||||
|
||||
RemoteSpeaker::RemoteSpeaker()
|
||||
: mInitFlag(false),
|
||||
mPlayFlag(false),
|
||||
mEnableFlag(false),
|
||||
mFirstEncodeFlag(false),
|
||||
mValidCallbackFlag(false),
|
||||
mCommandBusyFlag(false),
|
||||
// mForceResumeFlag(false),
|
||||
mState(STATE_INVALID),
|
||||
mUserCommand(COMMAND_NONE),
|
||||
mInternalCommand(COMMAND_NONE),
|
||||
mWpadCallback(nullptr) {
|
||||
|
||||
OSCreateAlarm(&mContinueAlarm);
|
||||
OSSetAlarmUserData(&mContinueAlarm, this);
|
||||
|
||||
OSCreateAlarm(&mIntervalAlarm);
|
||||
OSSetAlarmUserData(&mIntervalAlarm, this);
|
||||
}
|
||||
|
||||
void RemoteSpeaker::InitParam() {
|
||||
ClearParam();
|
||||
|
||||
// mForceResumeFlag = false;
|
||||
mContinueFlag = false;
|
||||
mPlayFlag = false;
|
||||
mEnableFlag = true;
|
||||
mIntervalFlag = false;
|
||||
}
|
||||
|
||||
void RemoteSpeaker::ClearParam() {
|
||||
mPlayFlag = false;
|
||||
mEnableFlag = false;
|
||||
|
||||
OSCancelAlarm(&mContinueAlarm);
|
||||
mContinueFlag = false;
|
||||
|
||||
OSCancelAlarm(&mIntervalAlarm);
|
||||
mIntervalFlag = false;
|
||||
}
|
||||
|
||||
bool RemoteSpeaker::Setup(WPADCallback pCallback) {
|
||||
ut::AutoInterruptLock lock;
|
||||
|
||||
InitParam();
|
||||
|
||||
if (mWpadCallback != NULL) {
|
||||
mWpadCallback(mChannelIndex, WPAD_ERR_OK);
|
||||
mValidCallbackFlag = false;
|
||||
}
|
||||
|
||||
mWpadCallback = pCallback;
|
||||
mUserCommand = COMMAND_SPEAKER_ON;
|
||||
mInitFlag = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void RemoteSpeaker::Shutdown(WPADCallback pCallback) {
|
||||
ut::AutoInterruptLock lock;
|
||||
|
||||
ClearParam();
|
||||
|
||||
if (mWpadCallback != NULL) {
|
||||
mWpadCallback(mChannelIndex, WPAD_ERR_OK);
|
||||
mValidCallbackFlag = false;
|
||||
}
|
||||
|
||||
mUserCommand = COMMAND_SPEAKER_OFF;
|
||||
mWpadCallback = pCallback;
|
||||
mInitFlag = false;
|
||||
}
|
||||
|
||||
bool RemoteSpeaker::EnableOutput(bool enable) {
|
||||
if (!mInitFlag) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mEnableFlag = enable;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RemoteSpeaker::IsEnabledOutput() const {
|
||||
if (!mInitFlag) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return mEnableFlag;
|
||||
}
|
||||
|
||||
void RemoteSpeaker::Update() {
|
||||
if (mCommandBusyFlag) {
|
||||
return;
|
||||
}
|
||||
|
||||
SpeakerCommand command =
|
||||
mUserCommand != COMMAND_NONE ? mUserCommand : mInternalCommand;
|
||||
|
||||
mUserCommand = COMMAND_NONE;
|
||||
mInternalCommand = COMMAND_NONE;
|
||||
|
||||
ExecCommand(command);
|
||||
}
|
||||
|
||||
void RemoteSpeaker::ExecCommand(SpeakerCommand command) {
|
||||
switch (command) {
|
||||
case COMMAND_NONE: {
|
||||
break;
|
||||
}
|
||||
|
||||
case COMMAND_SPEAKER_ON: {
|
||||
mValidCallbackFlag = true;
|
||||
mCommandBusyFlag = true;
|
||||
mState = STATE_EXEC_SPEAKER_ON;
|
||||
WPADControlSpeaker(mChannelIndex, WPAD_SPEAKER_ON, SpeakerOnCallback);
|
||||
break;
|
||||
}
|
||||
|
||||
case COMMAND_SPEAKER_PLAY: {
|
||||
mValidCallbackFlag = true;
|
||||
mCommandBusyFlag = true;
|
||||
mState = STATE_EXEC_SPEAKER_PLAY;
|
||||
WPADControlSpeaker(mChannelIndex, WPAD_SPEAKER_PLAY,
|
||||
SpeakerPlayCallback);
|
||||
break;
|
||||
}
|
||||
|
||||
case COMMAND_SPEAKER_OFF: {
|
||||
mValidCallbackFlag = true;
|
||||
mCommandBusyFlag = true;
|
||||
mState = STATE_EXEC_SPEAKER_OFF;
|
||||
WPADControlSpeaker(mChannelIndex, WPAD_SPEAKER_OFF, SpeakerOffCallback);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RemoteSpeaker::UpdateStreamData(const s16* pRmtSamples) {
|
||||
if (!IsAvailable()) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool playFlag = true;
|
||||
bool silentFlag = mEnableFlag ? IsAllSampleZero(pRmtSamples) : true;
|
||||
|
||||
if (silentFlag /*|| mForceResumeFlag*/) {
|
||||
playFlag = false;
|
||||
}
|
||||
|
||||
bool firstFlag = !mPlayFlag && playFlag;
|
||||
bool lastFlag = mPlayFlag && !playFlag;
|
||||
|
||||
if (playFlag) {
|
||||
ut::AutoInterruptLock lock;
|
||||
|
||||
if (!WPADCanSendStreamData(mChannelIndex)) {
|
||||
return;
|
||||
}
|
||||
|
||||
u32 wencMode = !mFirstEncodeFlag ? WENC_FLAG_USER_INFO : 0;
|
||||
mFirstEncodeFlag = false;
|
||||
|
||||
u8 adpcmBuffer[SAMPLES_PER_ENCODED_PACKET];
|
||||
WENCGetEncodeData(&mEncodeInfo, wencMode, pRmtSamples,
|
||||
SAMPLES_PER_AUDIO_PACKET, adpcmBuffer);
|
||||
|
||||
s32 result = WPADSendStreamData(mChannelIndex, adpcmBuffer,
|
||||
SAMPLES_PER_ENCODED_PACKET);
|
||||
if (result != WPAD_ERR_OK) {
|
||||
mInternalCommand = COMMAND_SPEAKER_ON;
|
||||
mState = STATE_INVALID;
|
||||
InitParam();
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (firstFlag) {
|
||||
ut::AutoInterruptLock lock;
|
||||
|
||||
if (!mContinueFlag) {
|
||||
OSSetAlarm(&mContinueAlarm,
|
||||
OS_SEC_TO_TICKS(CONTINUOUS_PLAY_INTERVAL_MINUTES * 60LL),
|
||||
ContinueAlarmHandler);
|
||||
|
||||
mContinueBeginTime = OSGetTime();
|
||||
mContinueFlag = true;
|
||||
}
|
||||
|
||||
OSCancelAlarm(&mIntervalAlarm);
|
||||
mIntervalFlag = false;
|
||||
}
|
||||
|
||||
if (lastFlag) {
|
||||
ut::AutoInterruptLock lock;
|
||||
|
||||
mIntervalFlag = true;
|
||||
OSCancelAlarm(&mIntervalAlarm);
|
||||
OSSetAlarm(&mIntervalAlarm, OS_SEC_TO_TICKS(1LL), IntervalAlarmHandler);
|
||||
}
|
||||
|
||||
mPlayFlag = playFlag;
|
||||
}
|
||||
|
||||
bool RemoteSpeaker::IsAllSampleZero(const s16* pSample) {
|
||||
const u32* pBuffer = reinterpret_cast<const u32*>(pSample);
|
||||
bool zeroFlag = true;
|
||||
|
||||
for (int i = 0; i < SAMPLES_PER_ENCODED_PACKET; i++) {
|
||||
if (pBuffer[i] != 0) {
|
||||
zeroFlag = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return zeroFlag;
|
||||
}
|
||||
|
||||
void RemoteSpeaker::SpeakerOnCallback(s32 chan, s32 result) {
|
||||
RemoteSpeaker& r =
|
||||
detail::RemoteSpeakerManager::GetInstance().GetRemoteSpeaker(chan);
|
||||
|
||||
switch (result) {
|
||||
case WPAD_ERR_OK: {
|
||||
r.mFirstEncodeFlag = true;
|
||||
std::memset(&r.mEncodeInfo, 0, sizeof(WENCInfo));
|
||||
|
||||
r.mState = STATE_SPEAKER_ON;
|
||||
r.mInternalCommand = COMMAND_SPEAKER_PLAY;
|
||||
break;
|
||||
}
|
||||
|
||||
case WPAD_ERR_BUSY: {
|
||||
r.mInternalCommand = COMMAND_SPEAKER_ON;
|
||||
break;
|
||||
}
|
||||
|
||||
case WPAD_ERR_TRANSFER: {
|
||||
r.mState = STATE_INVALID;
|
||||
break;
|
||||
}
|
||||
|
||||
case WPAD_ERR_NO_CONTROLLER: {
|
||||
r.mState = STATE_INVALID;
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
r.mState = STATE_INVALID;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (result != WPAD_ERR_OK && result != WPAD_ERR_BUSY) {
|
||||
r.NotifyCallback(chan, result);
|
||||
}
|
||||
|
||||
r.mCommandBusyFlag = false;
|
||||
}
|
||||
|
||||
void RemoteSpeaker::SpeakerPlayCallback(s32 chan, s32 result) {
|
||||
RemoteSpeaker& r =
|
||||
detail::RemoteSpeakerManager::GetInstance().GetRemoteSpeaker(chan);
|
||||
|
||||
switch (result) {
|
||||
case WPAD_ERR_OK: {
|
||||
r.mState = STATE_SPEAKER_PLAY;
|
||||
break;
|
||||
}
|
||||
|
||||
case WPAD_ERR_BUSY: {
|
||||
r.mInternalCommand = COMMAND_SPEAKER_PLAY;
|
||||
break;
|
||||
}
|
||||
|
||||
case WPAD_ERR_TRANSFER: {
|
||||
r.mState = STATE_INVALID;
|
||||
break;
|
||||
}
|
||||
|
||||
case WPAD_ERR_NO_CONTROLLER: {
|
||||
r.mState = STATE_INVALID;
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
r.mState = STATE_INVALID;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (result != WPAD_ERR_BUSY) {
|
||||
r.NotifyCallback(chan, result);
|
||||
}
|
||||
|
||||
r.mCommandBusyFlag = false;
|
||||
}
|
||||
|
||||
void RemoteSpeaker::SpeakerOffCallback(s32 chan, s32 result) {
|
||||
RemoteSpeaker& r =
|
||||
detail::RemoteSpeakerManager::GetInstance().GetRemoteSpeaker(chan);
|
||||
|
||||
switch (result) {
|
||||
case WPAD_ERR_OK: {
|
||||
r.mState = STATE_SPEAKER_OFF;
|
||||
break;
|
||||
}
|
||||
|
||||
case WPAD_ERR_BUSY: {
|
||||
r.mInternalCommand = COMMAND_SPEAKER_OFF;
|
||||
break;
|
||||
}
|
||||
|
||||
case WPAD_ERR_TRANSFER: {
|
||||
r.mState = STATE_INVALID;
|
||||
break;
|
||||
}
|
||||
|
||||
case WPAD_ERR_NO_CONTROLLER: {
|
||||
r.mState = STATE_INVALID;
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
r.mState = STATE_INVALID;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (result != WPAD_ERR_BUSY) {
|
||||
r.NotifyCallback(chan, result);
|
||||
}
|
||||
|
||||
r.mCommandBusyFlag = false;
|
||||
}
|
||||
|
||||
void RemoteSpeaker::NotifyCallback(s32 chan, s32 result) {
|
||||
if (mValidCallbackFlag && mWpadCallback != NULL) {
|
||||
mWpadCallback(chan, result);
|
||||
mWpadCallback = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void RemoteSpeaker::ContinueAlarmHandler(OSAlarm* pAlarm, OSContext* pCtx) {
|
||||
#pragma unused(pCtx)
|
||||
|
||||
ut::AutoInterruptLock lock;
|
||||
RemoteSpeaker* p = static_cast<RemoteSpeaker*>(OSGetAlarmUserData(pAlarm));
|
||||
|
||||
// p->mForceResumeFlag = true;
|
||||
p->mContinueFlag = false;
|
||||
}
|
||||
|
||||
void RemoteSpeaker::IntervalAlarmHandler(OSAlarm* pAlarm, OSContext* pCtx) {
|
||||
#pragma unused(pCtx)
|
||||
|
||||
ut::AutoInterruptLock lock;
|
||||
RemoteSpeaker* p = static_cast<RemoteSpeaker*>(OSGetAlarmUserData(pAlarm));
|
||||
|
||||
if (p->mIntervalFlag) {
|
||||
OSCancelAlarm(&p->mContinueAlarm);
|
||||
// p->mForceResumeFlag = false;
|
||||
p->mContinueFlag = false;
|
||||
}
|
||||
|
||||
p->mIntervalFlag = false;
|
||||
}
|
||||
|
||||
} // namespace snd
|
||||
} // namespace nw4r
|
||||
|
||||
@@ -1 +1,75 @@
|
||||
#include "nw4r/snd/snd_RemoteSpeakerManager.h"
|
||||
#include "rvl/AX/AXOut.h"
|
||||
|
||||
|
||||
namespace nw4r {
|
||||
namespace snd {
|
||||
namespace detail {
|
||||
|
||||
RemoteSpeakerManager& RemoteSpeakerManager::GetInstance() {
|
||||
static RemoteSpeakerManager instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
RemoteSpeakerManager::RemoteSpeakerManager() : mInitialized(false) {
|
||||
for (int i = 0; i < WPAD_MAX_CONTROLLERS; i++) {
|
||||
mSpeaker[i].SetChannelIndex(i);
|
||||
}
|
||||
}
|
||||
|
||||
RemoteSpeaker& RemoteSpeakerManager::GetRemoteSpeaker(int idx) {
|
||||
return mSpeaker[idx];
|
||||
}
|
||||
|
||||
void RemoteSpeakerManager::Setup() {
|
||||
if (mInitialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
OSCreateAlarm(&mRemoteSpeakerAlarm);
|
||||
|
||||
OSSetPeriodicAlarm(&mRemoteSpeakerAlarm, OSGetTime(),
|
||||
OS_NSEC_TO_TICKS(SPEAKER_ALARM_PERIOD_NSEC),
|
||||
RemoteSpeakerAlarmProc);
|
||||
|
||||
mInitialized = true;
|
||||
}
|
||||
|
||||
void RemoteSpeakerManager::Shutdown() {
|
||||
if (!mInitialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
OSCancelAlarm(&mRemoteSpeakerAlarm);
|
||||
mInitialized = false;
|
||||
}
|
||||
|
||||
void RemoteSpeakerManager::RemoteSpeakerAlarmProc(OSAlarm* pAlarm,
|
||||
OSContext* pCtx) {
|
||||
#pragma unused(pAlarm)
|
||||
#pragma unused(pCtx)
|
||||
|
||||
RemoteSpeakerManager& r = GetInstance();
|
||||
|
||||
s16 samples[RemoteSpeaker::SAMPLES_PER_AUDIO_PACKET];
|
||||
if (AXRmtGetSamplesLeft() < RemoteSpeaker::SAMPLES_PER_AUDIO_PACKET) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < WPAD_MAX_CONTROLLERS; i++) {
|
||||
if (r.mSpeaker[i].IsAvailable()) {
|
||||
AXRmtGetSamples(i, samples,
|
||||
RemoteSpeaker::SAMPLES_PER_AUDIO_PACKET);
|
||||
|
||||
r.mSpeaker[i].UpdateStreamData(samples);
|
||||
}
|
||||
|
||||
r.mSpeaker[i].Update();
|
||||
}
|
||||
|
||||
AXRmtAdvancePtr(RemoteSpeaker::SAMPLES_PER_AUDIO_PACKET);
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace snd
|
||||
} // namespace nw4r
|
||||
|
||||
@@ -241,6 +241,10 @@ void SeqPlayer::Skip(OffsetType offsetType, int offset)
|
||||
// SeqPlayer::SetTempoRatio ([R89JEL]:/bin/RVL/Debug/mainD.MAP:13781)
|
||||
DECOMP_FORCE(NW4RAssert_String(tempoRatio >= 0.0f));
|
||||
|
||||
void SeqPlayer::SetTempoRatio(f32 tempo) {
|
||||
mTempoRatio = tempo;
|
||||
}
|
||||
|
||||
void SeqPlayer::SetChannelPriority(int priority)
|
||||
{
|
||||
// specifically not the source variant
|
||||
|
||||
@@ -169,6 +169,10 @@ void SeqSound::Shutdown()
|
||||
// SeqSound::SetTempoRatio ([R89JEL]:/bin/RVL/Debug/mainD.MAP:13849)
|
||||
DECOMP_FORCE(NW4RAssert_String(tempoRatio >= 0.0f));
|
||||
|
||||
void SeqSound::SetTempoRatio(f32 tempo) {
|
||||
mSeqPlayer.SetTempoRatio(tempo);
|
||||
}
|
||||
|
||||
void SeqSound::SetChannelPriority(int priority)
|
||||
{
|
||||
// specifically not the source variant
|
||||
|
||||
@@ -1 +1,294 @@
|
||||
#include "nw4r/snd/snd_Sound3DManager.h"
|
||||
#include "nw4r/snd/snd_AxManager.h"
|
||||
#include "nw4r/snd/snd_Sound3DListener.h"
|
||||
#include "nw4r/snd/snd_SoundHandle.h"
|
||||
|
||||
#include "nw4r/math.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
namespace nw4r {
|
||||
namespace snd {
|
||||
namespace {
|
||||
|
||||
/**
|
||||
* Solves the linear equation:
|
||||
* a*x + b*y + c = d
|
||||
*
|
||||
* Where:
|
||||
* a = dFactor - cFactor
|
||||
* b = dAngle - cAngle
|
||||
* c = cAngle * cFactor
|
||||
* d = dAngle * dFactor
|
||||
*/
|
||||
inline f32 SolveLinerFunction(f32 x, f32 dAngle, f32 cAngle, f32 dFactor,
|
||||
f32 cFactor) { // @typo
|
||||
if (dAngle == cAngle) {
|
||||
return (dFactor + cFactor) / 2;
|
||||
}
|
||||
|
||||
f32 b = dAngle - cAngle;
|
||||
|
||||
return x * (cFactor - dFactor) / b +
|
||||
(dAngle * dFactor - cAngle * cFactor) / b;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Sound3DManager::Sound3DManager()
|
||||
: mMaxPriorityReduction(32),
|
||||
mSpeakerAngleStereo(NW4R_MATH_PI / 4),
|
||||
mFrontSpeakerAngleDpl2(NW4R_MATH_PI / 6),
|
||||
mRearSpeakerAngleDpl2(2 * NW4R_MATH_PI / 3),
|
||||
mInitPan(0.0f),
|
||||
mPanRange(0.9f) {}
|
||||
|
||||
u32 Sound3DManager::GetRequiredMemSize(const SoundArchive* pArchive) {
|
||||
u32 numParam = 0;
|
||||
|
||||
SoundArchive::SoundArchivePlayerInfo playerInfo;
|
||||
if (pArchive->ReadSoundArchivePlayerInfo(&playerInfo)) {
|
||||
numParam += playerInfo.seqSoundCount;
|
||||
numParam += playerInfo.strmSoundCount;
|
||||
numParam += playerInfo.waveSoundCount;
|
||||
}
|
||||
|
||||
return numParam * sizeof(Sound3DActorParam);
|
||||
}
|
||||
|
||||
bool Sound3DManager::Setup(const SoundArchive* pArchive, void* pBuffer,
|
||||
u32 size) {
|
||||
#pragma unused(pArchive)
|
||||
|
||||
mParamPool.Create(pBuffer, size);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Sound3DManager::detail_Update(SoundParam* pParam, u32 id,
|
||||
detail::BasicSound* pSound, const void* pArg,
|
||||
u32 flags) {
|
||||
SoundHandle handle;
|
||||
if (pSound != NULL) {
|
||||
handle.detail_AttachSoundAsTempHandle(pSound);
|
||||
}
|
||||
|
||||
Update(pParam, id, pSound != NULL ? &handle : NULL, pArg, flags);
|
||||
}
|
||||
|
||||
void Sound3DManager::Update(SoundParam* pParam, u32 id, SoundHandle* pHandle,
|
||||
const void* pArg, u32 flags) {
|
||||
#pragma unused(id)
|
||||
#pragma unused(pHandle)
|
||||
|
||||
f32 angle;
|
||||
f32 panLR, panFR;
|
||||
f32 pan, surroundPan;
|
||||
|
||||
const Sound3DActorParam* pActorParam =
|
||||
static_cast<const Sound3DActorParam*>(pArg);
|
||||
|
||||
Sound3DListener* pListener = GetListener();
|
||||
if (pListener == NULL) {
|
||||
pParam->volume = 0.0f;
|
||||
return;
|
||||
}
|
||||
|
||||
math::VEC3 relativePos;
|
||||
VEC3Transform(&relativePos, &pListener->GetMatrix(),
|
||||
&pActorParam->position);
|
||||
|
||||
f32 distance = VEC3Len(&relativePos);
|
||||
f32 volume = 1.0f;
|
||||
|
||||
if ((flags & (PARAM_UPDATE_VOLUME | PARAM_UPDATE_PRIORITY)) &&
|
||||
distance > pListener->GetMaxVolumeDistance()) {
|
||||
|
||||
switch (pActorParam->soundParam.decayCurve) {
|
||||
case DECAY_CURVE_LOGARITHMIC: {
|
||||
f32 units = (distance - pListener->GetMaxVolumeDistance()) /
|
||||
pListener->GetUnitDistance();
|
||||
|
||||
volume =
|
||||
std::pow(pActorParam->soundParam.decayRatio / 256.0f, units);
|
||||
break;
|
||||
}
|
||||
|
||||
case DECAY_CURVE_LINEAR: {
|
||||
f32 units = (distance - pListener->GetMaxVolumeDistance()) /
|
||||
pListener->GetUnitDistance() *
|
||||
pActorParam->soundParam.decayRatio;
|
||||
|
||||
units = units / 256.0f;
|
||||
volume = ut::Max(0.0f, 1.0f - units);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((flags & PARAM_UPDATE_VOLUME) &&
|
||||
!(pActorParam->soundParam.flags & PARAM_UPDATE_VOLUME)) {
|
||||
|
||||
pParam->volume = volume;
|
||||
}
|
||||
|
||||
if (flags & (PARAM_UPDATE_PAN | PARAM_UPDATE_SURROUND_PAN)) {
|
||||
math::VEC3 adjustedPos;
|
||||
|
||||
if (0.0f == distance) {
|
||||
adjustedPos.z = 0.0f;
|
||||
adjustedPos.y = 0.0f;
|
||||
adjustedPos.x = 0.0f;
|
||||
} else {
|
||||
math::VEC3 relativeXZ(relativePos.x, 0.0f, relativePos.z);
|
||||
|
||||
f32 distanceXZ = VEC3Len(&relativeXZ);
|
||||
if (distanceXZ > pListener->GetInteriorSize()) {
|
||||
relativeXZ.x *= pListener->GetInteriorSize() / distanceXZ;
|
||||
relativeXZ.z *= pListener->GetInteriorSize() / distanceXZ;
|
||||
}
|
||||
|
||||
f32 ratioXZ = VEC3Len(&relativeXZ);
|
||||
adjustedPos.x = relativePos.x * ratioXZ / distance;
|
||||
adjustedPos.y = 0.0f;
|
||||
adjustedPos.z = relativePos.z * ratioXZ / distance;
|
||||
}
|
||||
|
||||
angle = atan2(adjustedPos.x, -adjustedPos.z);
|
||||
f32 distanceNrm = VEC3Len(&adjustedPos) / pListener->GetInteriorSize();
|
||||
|
||||
switch (detail::AxManager::GetInstance().GetOutputMode()) {
|
||||
case OUTPUT_MODE_SURROUND:
|
||||
case OUTPUT_MODE_DPL2: {
|
||||
static f32 angleRearLeft = -mRearSpeakerAngleDpl2;
|
||||
static f32 angleFrontLeft = -mFrontSpeakerAngleDpl2;
|
||||
static f32 angleFrontRight = mFrontSpeakerAngleDpl2;
|
||||
static f32 angleRearRight = mRearSpeakerAngleDpl2;
|
||||
|
||||
// clang-format off
|
||||
if (angle < angleRearLeft) {
|
||||
panLR = SolveLinerFunction(angle, -NW4R_MATH_PI, angleRearLeft, -1.0f, 0.0f);
|
||||
panFR = 1.0f;
|
||||
} else if (angle < -NW4R_MATH_PI / 2) {
|
||||
panLR = -1.0f;
|
||||
panFR = SolveLinerFunction(angle, angleRearLeft, -NW4R_MATH_PI / 2, 0.0f, 1.0f);
|
||||
} else if (angle < angleFrontLeft) {
|
||||
panLR = -1.0f;
|
||||
panFR = SolveLinerFunction(angle, -NW4R_MATH_PI / 2, angleFrontLeft, -1.0f, 0.0f);
|
||||
} else if (angle < angleFrontRight) {
|
||||
panLR = SolveLinerFunction(angle, angleFrontLeft, angleFrontRight, 1.0f, -1.0f);
|
||||
panFR = -1.0f;
|
||||
} else if (angle < NW4R_MATH_PI / 2) {
|
||||
panLR = 1.0f;
|
||||
panFR = SolveLinerFunction(angle, angleFrontRight, NW4R_MATH_PI / 2, 0.0f, -1.0f);
|
||||
} else if (angle < angleRearRight) {
|
||||
panLR = 1.0f;
|
||||
panFR = SolveLinerFunction(angle, NW4R_MATH_PI / 2, angleRearRight, 1.0f, 0.0f);
|
||||
} else {
|
||||
panLR = SolveLinerFunction(angle, angleRearRight, NW4R_MATH_PI, 0.0f, 1.0f);
|
||||
panFR = 1.0f;
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
f32 cosAvg = (std::cosf(mFrontSpeakerAngleDpl2) +
|
||||
std::cosf(mRearSpeakerAngleDpl2)) /
|
||||
2.0f;
|
||||
|
||||
f32 rearFactor =
|
||||
cosAvg / (cosAvg + -std::cosf(mRearSpeakerAngleDpl2));
|
||||
|
||||
panLR *= mPanRange;
|
||||
panFR *= mPanRange;
|
||||
|
||||
pan = panLR * distanceNrm;
|
||||
|
||||
surroundPan =
|
||||
mInitPan + (1.0f + (panFR * distanceNrm +
|
||||
rearFactor * (1.0f - distanceNrm)));
|
||||
break;
|
||||
}
|
||||
|
||||
case OUTPUT_MODE_STEREO: {
|
||||
static f32 angleRearLeft = -NW4R_MATH_PI + mSpeakerAngleStereo;
|
||||
static f32 angleFrontLeft = -mSpeakerAngleStereo;
|
||||
static f32 angleFrontRight = mSpeakerAngleStereo;
|
||||
static f32 angleRearRight = NW4R_MATH_PI - mSpeakerAngleStereo;
|
||||
|
||||
// clang-format off
|
||||
if (angle < angleRearLeft) {
|
||||
panLR = SolveLinerFunction(angle, -NW4R_MATH_PI, angleRearLeft, -1.0f, 0.0f);
|
||||
panFR = 1.0f;
|
||||
} else if (angle < angleFrontLeft) {
|
||||
panLR = -1.0f;
|
||||
panFR = SolveLinerFunction(angle, angleRearLeft, angleFrontLeft, -1.0f, 1.0f);
|
||||
} else if (angle < angleFrontRight) {
|
||||
panLR = SolveLinerFunction(angle, angleFrontLeft, angleFrontRight, 1.0f, -1.0f);
|
||||
panFR = -1.0f;
|
||||
} else if (angle < angleRearRight) {
|
||||
panLR = 1.0f;
|
||||
panFR = SolveLinerFunction(angle, angleFrontRight, angleRearRight, 1.0f, -1.0f);
|
||||
} else {
|
||||
panLR = SolveLinerFunction(angle, angleRearRight, NW4R_MATH_PI, 0.0f, 1.0f);
|
||||
panFR = 1.0f;
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
panLR *= mPanRange;
|
||||
panFR *= mPanRange;
|
||||
|
||||
surroundPan = 1.0f + panFR * distanceNrm;
|
||||
pan = panLR * distanceNrm;
|
||||
break;
|
||||
}
|
||||
|
||||
case OUTPUT_MODE_MONO:
|
||||
default: {
|
||||
pan = 0.0f;
|
||||
surroundPan = 0.0f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((flags & PARAM_UPDATE_PAN) &&
|
||||
!(pActorParam->soundParam.flags & PARAM_UPDATE_PAN)) {
|
||||
|
||||
pParam->pan = pan;
|
||||
}
|
||||
|
||||
if ((flags & PARAM_UPDATE_SURROUND_PAN) &&
|
||||
!(pActorParam->soundParam.flags & PARAM_UPDATE_SURROUND_PAN)) {
|
||||
|
||||
pParam->surroundPan = surroundPan;
|
||||
}
|
||||
|
||||
if ((flags & PARAM_UPDATE_PRIORITY) &&
|
||||
!(pActorParam->soundParam.flags & PARAM_UPDATE_PRIORITY)) {
|
||||
|
||||
pParam->priority =
|
||||
-static_cast<int>((1.0f - volume) * GetMaxPriorityReduction());
|
||||
}
|
||||
}
|
||||
|
||||
void* Sound3DManager::detail_AllocAmbientArg(u32 size) {
|
||||
if (size != sizeof(Sound3DActorParam)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return mParamPool.Alloc();
|
||||
}
|
||||
|
||||
void Sound3DManager::detail_FreeAmbientArg(void* pArg,
|
||||
const detail::BasicSound* pSound) {
|
||||
#pragma unused(pSound)
|
||||
|
||||
mParamPool.Free(static_cast<Sound3DActorParam*>(pArg));
|
||||
}
|
||||
|
||||
Sound3DManager::Sound3DActorParam::Sound3DActorParam() : userParam(-1) {
|
||||
soundParam.flags = 0;
|
||||
soundParam.decayCurve = DECAY_CURVE_LOGARITHMIC;
|
||||
soundParam.decayRatio = 128;
|
||||
}
|
||||
|
||||
} // namespace snd
|
||||
} // namespace nw4r
|
||||
|
||||
@@ -72,11 +72,27 @@ u32 SoundArchive::GetGroupCount() const
|
||||
return mFileReader->GetGroupCount();
|
||||
}
|
||||
|
||||
const char* SoundArchive::GetSoundLabelString(u32 id) const {
|
||||
return mFileReader->GetSoundLabelString(id);
|
||||
}
|
||||
|
||||
u32 SoundArchive::ConvertLabelStringToSoundId(char const *label) const
|
||||
{
|
||||
return mFileReader->ConvertLabelStringToSoundId(label);
|
||||
}
|
||||
|
||||
u32 SoundArchive::ConvertLabelStringToPlayerId(const char* pLabel) const {
|
||||
return mFileReader->ConvertLabelStringToPlayerId(pLabel);
|
||||
}
|
||||
|
||||
u32 SoundArchive::ConvertLabelStringToGroupId(const char* pLabel) const {
|
||||
return mFileReader->ConvertLabelStringToGroupId(pLabel);
|
||||
}
|
||||
|
||||
u32 SoundArchive::GetSoundUserParam(u32 id) const {
|
||||
return mFileReader->GetSoundUserParam(id);
|
||||
}
|
||||
|
||||
SoundArchive::SoundType SoundArchive::GetSoundType(u32 soundId) const
|
||||
{
|
||||
return mFileReader->GetSoundType(soundId);
|
||||
@@ -226,4 +242,52 @@ ut::FileStream *SoundArchive::OpenExtStreamImpl(void *buffer, int size,
|
||||
return OpenExtStream(buffer, size, fullPath, begin, length);
|
||||
}
|
||||
|
||||
ut::FileStream* SoundArchive::detail_OpenGroupStream(u32 id, void* pBuffer,
|
||||
int bufferSize) const {
|
||||
GroupInfo groupInfo;
|
||||
if (!detail_ReadGroupInfo(id, &groupInfo)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (groupInfo.extFilePath != NULL) {
|
||||
return OpenExtStreamImpl(pBuffer, bufferSize, groupInfo.extFilePath,
|
||||
groupInfo.offset, groupInfo.size);
|
||||
}
|
||||
|
||||
return OpenStream(pBuffer, bufferSize, groupInfo.offset, groupInfo.size);
|
||||
}
|
||||
|
||||
ut::FileStream*
|
||||
SoundArchive::detail_OpenGroupWaveDataStream(u32 id, void* pBuffer,
|
||||
int bufferSize) const {
|
||||
GroupInfo groupInfo;
|
||||
if (!detail_ReadGroupInfo(id, &groupInfo)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (groupInfo.extFilePath != NULL) {
|
||||
return OpenExtStreamImpl(pBuffer, bufferSize, groupInfo.extFilePath,
|
||||
groupInfo.waveDataOffset,
|
||||
groupInfo.waveDataSize);
|
||||
}
|
||||
|
||||
return OpenStream(pBuffer, bufferSize, groupInfo.waveDataOffset,
|
||||
groupInfo.waveDataSize);
|
||||
}
|
||||
|
||||
void SoundArchive::SetExternalFileRoot(const char* pExtFileRoot) {
|
||||
u32 len = std::strlen(pExtFileRoot);
|
||||
u32 nullPos = len;
|
||||
|
||||
if (pExtFileRoot[len - 1] != '/') {
|
||||
mExtFileRoot[len] = '/';
|
||||
nullPos++;
|
||||
}
|
||||
|
||||
mExtFileRoot[nullPos] = '\0';
|
||||
|
||||
// @bug Long path can overflow mExtFileRoot buffer
|
||||
std::strncpy(mExtFileRoot, pExtFileRoot, len);
|
||||
}
|
||||
|
||||
}} // namespace nw4r::snd
|
||||
|
||||
@@ -1 +1,139 @@
|
||||
#include "nw4r/snd/snd_SoundArchiveLoader.h"
|
||||
|
||||
#include "nw4r/snd/snd_SoundArchive.h"
|
||||
#include "nw4r/snd/snd_SoundMemoryAllocatable.h"
|
||||
|
||||
namespace nw4r {
|
||||
namespace snd {
|
||||
namespace detail {
|
||||
|
||||
SoundArchiveLoader::SoundArchiveLoader(const SoundArchive& rArchive)
|
||||
: mArc(rArchive), mStream(NULL) {
|
||||
OSInitMutex(&mMutex);
|
||||
}
|
||||
|
||||
SoundArchiveLoader::~SoundArchiveLoader() {}
|
||||
|
||||
void* SoundArchiveLoader::LoadGroup(u32 id,
|
||||
SoundMemoryAllocatable* pAllocatable,
|
||||
void** ppWaveBuffer, u32 blockSize) {
|
||||
ut::detail::AutoLock<OSMutex> lock(mMutex);
|
||||
|
||||
FileStreamHandle groupHandle(
|
||||
mArc.detail_OpenGroupStream(id, mStreamArea, sizeof(mStreamArea)));
|
||||
|
||||
if (!groupHandle) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!groupHandle->CanSeek() || !groupHandle->CanRead()) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void* pGroupBuffer = pAllocatable->Alloc(groupHandle->GetSize());
|
||||
if (pGroupBuffer == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mStream = groupHandle.GetFileStream();
|
||||
|
||||
if (blockSize == 0) {
|
||||
s32 bytesRead = groupHandle->Read(pGroupBuffer, groupHandle->GetSize());
|
||||
|
||||
if (bytesRead < 0) {
|
||||
mStream = NULL;
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
u8* pReadPtr = static_cast<u8*>(pGroupBuffer);
|
||||
u32 bytesLeft = groupHandle->GetSize();
|
||||
|
||||
while (bytesLeft) {
|
||||
s32 bytesRead =
|
||||
groupHandle->Read(pReadPtr, ut::Min(blockSize, bytesLeft));
|
||||
|
||||
if (bytesRead < 0) {
|
||||
mStream = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (bytesLeft > bytesRead) {
|
||||
bytesLeft -= bytesRead;
|
||||
pReadPtr += bytesRead;
|
||||
} else {
|
||||
bytesLeft = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mStream = NULL;
|
||||
|
||||
SoundArchive::GroupInfo groupInfo;
|
||||
if (!mArc.detail_ReadGroupInfo(id, &groupInfo)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (groupInfo.waveDataSize != 0) {
|
||||
FileStreamHandle waveHandle(mArc.detail_OpenGroupWaveDataStream(
|
||||
id, mStreamArea, sizeof(mStreamArea)));
|
||||
|
||||
if (!waveHandle) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!waveHandle->CanSeek() || !waveHandle->CanRead()) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void* pWaveBuffer = pAllocatable->Alloc(waveHandle->GetSize());
|
||||
if (pWaveBuffer == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mStream = waveHandle.GetFileStream();
|
||||
|
||||
if (blockSize == 0) {
|
||||
s32 bytesRead =
|
||||
waveHandle->Read(pWaveBuffer, waveHandle->GetSize());
|
||||
|
||||
if (bytesRead < 0) {
|
||||
mStream = NULL;
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
u8* pReadPtr = static_cast<u8*>(pWaveBuffer);
|
||||
u32 bytesLeft = waveHandle->GetSize();
|
||||
|
||||
while (bytesLeft) {
|
||||
s32 bytesRead =
|
||||
waveHandle->Read(pReadPtr, ut::Min(blockSize, bytesLeft));
|
||||
|
||||
if (bytesRead < 0) {
|
||||
mStream = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (bytesLeft > bytesRead) {
|
||||
bytesLeft -= bytesRead;
|
||||
pReadPtr += bytesRead;
|
||||
} else {
|
||||
bytesLeft = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mStream = NULL;
|
||||
|
||||
if (ppWaveBuffer != NULL) {
|
||||
*ppWaveBuffer = pWaveBuffer;
|
||||
}
|
||||
} else if (ppWaveBuffer != NULL) {
|
||||
*ppWaveBuffer = NULL;
|
||||
}
|
||||
|
||||
return pGroupBuffer;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace snd
|
||||
} // namespace nw4r
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
#include "nw4r/snd/snd_Bank.h"
|
||||
#include "nw4r/snd/snd_BasicSound.h"
|
||||
#include "nw4r/snd/snd_SoundArchiveLoader.h"
|
||||
#include "nw4r/snd/snd_debug.h"
|
||||
#include "nw4r/snd/snd_DisposeCallbackManager.h"
|
||||
#include "nw4r/snd/snd_ExternalSoundPlayer.h"
|
||||
@@ -1327,6 +1328,51 @@ void SoundArchivePlayer::UpdateCommonSoundParam(
|
||||
*/
|
||||
DECOMP_FORCE(NW4RAssertAligned_String(loadBlockSize, 32));
|
||||
|
||||
bool SoundArchivePlayer::LoadGroup(u32 id, SoundMemoryAllocatable* pAllocatable,
|
||||
u32 blockSize) {
|
||||
if (!IsAvailable()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (id >= mSoundArchive->GetGroupCount()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (GetGroupAddress(id) != NULL) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (pAllocatable == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
detail::SoundArchiveLoader loader(*mSoundArchive);
|
||||
|
||||
void* pWaveBuffer;
|
||||
const void* pGroup =
|
||||
loader.LoadGroup(id, pAllocatable, &pWaveBuffer, blockSize);
|
||||
|
||||
if (pGroup == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SetGroupAddress(id, pGroup);
|
||||
SetGroupWaveDataAddress(id, pWaveBuffer);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SoundArchivePlayer::LoadGroup(const char* pLabel,
|
||||
SoundMemoryAllocatable* pAllocatable,
|
||||
u32 blockSize) {
|
||||
u32 id = mSoundArchive->ConvertLabelStringToGroupId(pLabel);
|
||||
if (id == SoundArchive::INVALID_ID) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return LoadGroup(id, pAllocatable, blockSize);
|
||||
}
|
||||
|
||||
void SoundArchivePlayer::InvalidateData(void const *start, void const *end)
|
||||
{
|
||||
if (mFileTable)
|
||||
|
||||
@@ -21,6 +21,20 @@
|
||||
|
||||
namespace nw4r { namespace snd {
|
||||
|
||||
void SoundHandle::detail_AttachSoundAsTempHandle(detail::BasicSound* pSound) {
|
||||
mSound = pSound;
|
||||
|
||||
if (pSound->IsAttachedTempGeneralHandle()) {
|
||||
mSound->DetachTempGeneralHandle();
|
||||
}
|
||||
|
||||
if (mSound->IsAttachedTempSpecialHandle()) {
|
||||
mSound->DetachTempSpecialHandle();
|
||||
}
|
||||
|
||||
mSound->mTempGeneralHandle = this;
|
||||
}
|
||||
|
||||
void SoundHandle::detail_AttachSound(detail::BasicSound *sound)
|
||||
{
|
||||
NW4RAssertPointerNonnull_Line(81, sound);
|
||||
|
||||
@@ -1 +1,65 @@
|
||||
#include "nw4r/snd/snd_SoundHeap.h"
|
||||
|
||||
#include "nw4r/snd/snd_DisposeCallbackManager.h"
|
||||
#include "nw4r/snd/snd_SoundThread.h"
|
||||
|
||||
namespace nw4r {
|
||||
namespace snd {
|
||||
|
||||
SoundHeap::SoundHeap() {
|
||||
OSInitMutex(&mMutex);
|
||||
}
|
||||
|
||||
SoundHeap::~SoundHeap() {
|
||||
mFrameHeap.Destroy();
|
||||
}
|
||||
|
||||
bool SoundHeap::Create(void* pBase, u32 size) {
|
||||
return mFrameHeap.Create(pBase, size);
|
||||
}
|
||||
|
||||
void SoundHeap::Destroy() {
|
||||
mFrameHeap.Destroy();
|
||||
}
|
||||
|
||||
void* SoundHeap::Alloc(u32 size) {
|
||||
ut::detail::AutoLock<OSMutex> lock(mMutex);
|
||||
return mFrameHeap.Alloc(size, DisposeCallbackFunc, NULL);
|
||||
}
|
||||
|
||||
void* SoundHeap::Alloc(u32 size, detail::FrameHeap::FreeCallback pCallback,
|
||||
void* pCallbackArg) {
|
||||
ut::detail::AutoLock<OSMutex> lock(mMutex);
|
||||
return mFrameHeap.Alloc(size, pCallback, pCallbackArg);
|
||||
}
|
||||
|
||||
void SoundHeap::Clear() {
|
||||
ut::detail::AutoLock<OSMutex> lockHeap(mMutex);
|
||||
detail::SoundThread::AutoLock lockThread;
|
||||
|
||||
mFrameHeap.Clear();
|
||||
}
|
||||
|
||||
int SoundHeap::SaveState() {
|
||||
ut::detail::AutoLock<OSMutex> lock(mMutex);
|
||||
return mFrameHeap.SaveState();
|
||||
}
|
||||
|
||||
void SoundHeap::LoadState(int id) {
|
||||
ut::detail::AutoLock<OSMutex> lockHeap(mMutex);
|
||||
detail::SoundThread::AutoLock lockThread;
|
||||
|
||||
mFrameHeap.LoadState(id);
|
||||
}
|
||||
|
||||
void SoundHeap::DisposeCallbackFunc(void* pBuffer, u32 size,
|
||||
void* pCallbackArg) {
|
||||
detail::DisposeCallbackManager::GetInstance().Dispose(pBuffer, size,
|
||||
pCallbackArg);
|
||||
|
||||
detail::DisposeCallbackManager::GetInstance().DisposeWave(pBuffer, size,
|
||||
pCallbackArg);
|
||||
}
|
||||
|
||||
} // namespace snd
|
||||
} // namespace nw4r
|
||||
|
||||
@@ -78,6 +78,27 @@ namespace nw4r { namespace snd
|
||||
|
||||
namespace nw4r { namespace snd {
|
||||
|
||||
void SoundSystem::InitSoundSystem(s32 soundThreadPriority,
|
||||
s32 dvdThreadPriority) {
|
||||
const int defaultWorkSize = DEFAULT_SOUND_THREAD_STACK_SIZE +
|
||||
DEFAULT_DVD_THREAD_STACK_SIZE +
|
||||
detail::AxVoiceManager::WORK_SIZE_MAX +
|
||||
detail::VoiceManager::WORK_SIZE_MAX +
|
||||
detail::ChannelManager::WORK_SIZE_MAX;
|
||||
|
||||
static u8 defaultSoundSystemWork[defaultWorkSize] ALIGN_DECL(32);
|
||||
|
||||
// OSRegisterVersion(NW4R_SND_Version_);
|
||||
|
||||
SoundSystemParam param;
|
||||
param.soundThreadPriority = soundThreadPriority;
|
||||
param.dvdThreadPriority = dvdThreadPriority;
|
||||
|
||||
// @bug This function ignores the specified buffer size
|
||||
InitSoundSystem(param, defaultSoundSystemWork,
|
||||
sizeof(defaultSoundSystemWork));
|
||||
}
|
||||
|
||||
u32 SoundSystem::GetRequiredMemSize(SoundSystemParam const ¶m)
|
||||
{
|
||||
// could have just used align assert? idk
|
||||
@@ -210,6 +231,20 @@ bool SoundSystem::IsInitializedSoundSystem()
|
||||
return sInitialized;
|
||||
}
|
||||
|
||||
|
||||
void SoundSystem::WaitForResetReady() {
|
||||
if (!sInitialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
u32 start = OSGetTick();
|
||||
|
||||
while (!detail::AxManager::GetInstance().IsResetReady()) {
|
||||
if (OS_TICKS_TO_SEC(OSGetTick() - start) > 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// SoundSystem::WaitForResetReady ([R89JEL]:/bin/RVL/Debug/mainD.MAP:14493)
|
||||
DECOMP_FORCE("SoundSystem::WaitForResetReady is TIME OUT.\n");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user