Files
ss/include/nw4r/snd/snd_AxVoice.h
T
Elijah Thomas 26af4db82d update from dtk-template - clangd :) (#66)
* update from dtk-template and start work towards using clangd

* include <a> -> "a"

* Update build.yml

* remove/add non-trivial class in union warning
2024-10-16 15:36:02 -04:00

276 lines
6.9 KiB
C++

#ifndef NW4R_SND_AX_VOICE_H
#define NW4R_SND_AX_VOICE_H
#include "nw4r/snd/snd_Common.h"
#include "nw4r/types_nw4r.h"
#include "nw4r/ut.h" // IWYU pragma: export
#include "rvl/AX.h" // IWYU pragma: export
namespace nw4r {
namespace snd {
namespace detail {
class AxVoiceParamBlock {
public:
AxVoiceParamBlock();
operator AXVPB *() {
return mVpb;
}
bool IsAvailable() const {
return mVpb != NULL;
}
bool IsRun() const {
return IsAvailable() && mVpb->pb.state == AX_VOICE_RUN;
}
bool IsLpfEnable() const {
return IsAvailable() && mVpb->pb.lpf.on == AX_PB_LPF_ON;
}
bool IsBiquadEnable() const {
return IsAvailable() && mVpb->pb.biquad.on == AX_PB_BIQUAD_ON;
}
u32 GetCurrentAddress() const {
if (!IsAvailable()) {
return 0;
}
return (mVpb->pb.addr.currentAddressHi << 16) + mVpb->pb.addr.currentAddressLo;
}
u32 GetLoopAddress() const {
if (!IsAvailable()) {
return 0;
}
return (mVpb->pb.addr.loopAddressHi << 16) + mVpb->pb.addr.loopAddressLo;
}
u32 GetEndAddress() const {
if (!IsAvailable()) {
return 0;
}
return (mVpb->pb.addr.endAddressHi << 16) + mVpb->pb.addr.endAddressLo;
}
void SetVoiceAddr(const AXPBADDR &rAddr) {
if (IsAvailable()) {
// AXSetVoiceAddr doesn't actually modify the object
AXSetVoiceAddr(mVpb, const_cast<AXPBADDR *>(&rAddr));
}
}
void SetVoicePriority(u32 priority) {
if (IsAvailable()) {
AXSetVoicePriority(mVpb, priority);
}
}
void SetVoiceStateRun() {
if (IsAvailable()) {
AXSetVoiceState(mVpb, AX_VOICE_RUN);
}
}
void SetVoiceStateStop() {
if (IsRun()) {
AXSetVoiceState(mVpb, AX_VOICE_STOP);
}
}
void Sync();
bool IsRmtIirEnable() const;
void Set(AXVPB *pVpb);
void Clear();
void SetVoiceType(u16 type);
void SetVoiceVe(u16 volume, u16 initVolume);
void SetVoiceMix(const AXPBMIX &rMix, bool syncNow);
void SetVoiceLoop(u16 loop);
void SetVoiceLoopAddr(u32 addr);
void SetVoiceEndAddr(u32 addr);
void SetVoiceAdpcm(const AXPBADPCM &rAdpcm);
void SetVoiceSrcType(u32 type);
void SetVoiceSrc(const AXPBSRC &rSrc);
void SetVoiceSrcRatio(f32 ratio);
void SetVoiceAdpcmLoop(const AXPBADPCMLOOP &rLoop);
void SetVoiceLpf(const AXPBLPF &rLpf);
void SetVoiceLpfCoefs(u16 a0, u16 b0);
void SetVoiceRmtOn(u16 on);
void SetVoiceRmtMix(const AXPBRMTMIX &rMix);
void SetVoiceRmtIIR(const AXPBRMTIIR &rIir);
void SetVoiceRmtIIRCoefs(u16 type, ...);
void UpdateDelta();
private:
static const u16 DEFAULT_VOLUME = AX_MAX_VOLUME;
private:
AXVPB *mVpb; // at 0x0
u32 mSync; // at 0x4
volatile AXPBVE mPrevVeSetting; // at 0x8
bool mFirstVeUpdateFlag; // at 0xC
u16 mVolume; // at 0xE
};
class AxVoice {
friend class AxVoiceManager;
public:
enum AxVoiceCallbackStatus {
CALLBACK_STATUS_CANCEL,
CALLBACK_STATUS_DROP_DSP
};
typedef void (*AxVoiceCallback)(AxVoice *pDropVoice, AxVoiceCallbackStatus status, void *pArg);
enum Format {
FORMAT_ADPCM = 0,
FORMAT_PCM16 = 10,
FORMAT_PCM8 = 25,
};
enum VoiceType {
VOICE_TYPE_NORMAL,
VOICE_TYPE_STREAM,
};
enum SrcType {
SRC_NONE,
SRC_LINEAR,
SRC_4TAP_8K,
SRC_4TAP_12K,
SRC_4TAP_16K,
SRC_4TAP_AUTO,
};
struct MixParam {
u16 vL; // at 0x0
u16 vR; // at 0x2
u16 vS; // at 0x4
u16 vAuxAL; // at 0x6
u16 vAuxAR; // at 0x8
u16 vAuxAS; // at 0xA
u16 vAuxBL; // at 0xC
u16 vAuxBR; // at 0xE
u16 vAuxBS; // at 0x10
u16 vAuxCL; // at 0x12
u16 vAuxCR; // at 0x14
u16 vAuxCS; // at 0x16
};
struct RemoteMixParam {
u16 vMain0; // at 0x0
u16 vAux0; // at 0x2
u16 vMain1; // at 0x4
u16 vAux1; // at 0x6
u16 vMain2; // at 0x8
u16 vAux2; // at 0xA
u16 vMain3; // at 0xC
u16 vAux3; // at 0xE
};
public:
AxVoice();
~AxVoice();
bool IsRun() const {
return mVpb.IsRun();
}
void Run() {
mVpb.SetVoiceStateRun();
}
void Stop() {
mVpb.SetVoiceStateStop();
}
void Sync() {
mVpb.Sync();
}
Format GetFormat() const {
return mFormat;
}
void SetBaseAddress(const void *pBase) {
mWaveData = pBase;
}
f32 GetDspRatio(f32 ratio) const {
return (ratio * mSampleRate) / AX_SAMPLE_RATE;
}
void Setup(const void *pWave, Format fmt, int rate);
bool IsPlayFinished() const;
void SetLoopStart(const void *pBase, u32 samples);
void SetLoopEnd(const void *pBase, u32 samples);
void SetLoopFlag(bool loop);
void StopAtPoint(const void *pBase, u32 samples);
bool IsDataAddressCoverd(const void *pBegin, const void *pEnd) const;
u32 GetCurrentPlayingSample() const;
u32 GetCurrentPlayingDspAddress() const;
u32 GetLoopEndDspAddress() const;
void SetPriority(u32 priority);
void SetVoiceType(VoiceType type);
void EnableRemote(bool enable);
void ResetDelta();
void SetAddr(bool loop, const void *pWave, u32 offset, u32 loopStart, u32 loopEnd);
void SetSrcType(SrcType type, f32 pitch);
void SetAdpcm(const AdpcmParam *pParam);
void SetAdpcmLoop(const AdpcmLoopParam *pParam);
bool SetMix(const MixParam &rParam);
void SetRmtMix(const RemoteMixParam &rParam);
void SetSrc(f32 ratio, bool initial);
void SetVe(f32 volume, f32 initVolume);
void SetLpf(u16 freq);
void SetRemoteFilter(u8 filter);
static u32 GetDspAddressBySample(const void *pBase, u32 samples, Format fmt);
static u32 GetSampleByDspAddress(const void *pBase, u32 addr, Format fmt);
static u32 GetSampleByByte(u32 addr, Format fmt);
static void CalcOffsetAdpcmParam(
u16 *pPredScale, u16 *pYN1, u16 *pYN2, u32 offset, const void *pData, const AdpcmParam &rParam
);
private:
static void VoiceCallback(void *pArg);
private:
AxVoiceParamBlock mVpb; // at 0x0
const void *mWaveData; // at 0x10
Format mFormat; // at 0x14
int mSampleRate; // at 0x18
bool mFirstMixUpdateFlag; // at 0x1C
bool mReserveForFreeFlag; // at 0x1D
MixParam mMixPrev; // at 0x1E
AxVoiceCallback mCallback; // at 0x38
void *mCallbackData; // at 0x3C
public:
NW4R_UT_LIST_NODE_DECL(); // at 0x40
};
NW4R_UT_LIST_TYPEDEF_DECL(AxVoice);
inline int CalcAxvpbDelta(u16 init, u16 target) {
return (target - init) / AX_SAMPLES_PER_FRAME;
}
inline u16 CalcMixVolume(f32 volume) {
return ut::Min<u32>(0xFFFF, AX_MAX_VOLUME * volume);
}
} // namespace detail
} // namespace snd
} // namespace nw4r
#endif