diff --git a/CMakeLists.txt b/CMakeLists.txt index 9395f83759..583b5efa94 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -62,7 +62,6 @@ FetchContent_Declare( FetchContent_MakeAvailable(cxxopts) - include(files.cmake) # TODO: version handling for res includes @@ -81,7 +80,14 @@ source_group("dusk" FILES ${DUSK_FILES}) # game_debug is for game code files that we know work when compiled with DEBUG=1 # Of course, if building a release build, this distinction is irrelevant -add_library(game_debug STATIC ${JSYSTEM_DEBUG_FILES} ${SSYSTEM_FILES}) +add_library(game_debug STATIC ${JSYSTEM_DEBUG_FILES} ${SSYSTEM_FILES} + src/dusk/audio/DuskAudioSystem.cpp + src/dusk/audio/JASCriticalSection.cpp + src/dusk/audio/DuskDsp.hpp + src/dusk/audio/DuskDsp.cpp + src/dusk/audio/Adpcm.cpp + src/dusk/audio/Adpcm.hpp + src/dusk/audio/DspStub.cpp) target_compile_definitions(game_debug PRIVATE TARGET_PC AVOID_UB=1 VERSION=0 $<$:DEBUG=1>) # Make these properties PUBLIC so that the regular game target also sees them. @@ -98,7 +104,8 @@ target_link_libraries(game_debug PUBLIC aurora::core aurora::gx aurora::gd auror set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON) add_library(game SHARED ${DOLZEL_FILES} ${Z2AUDIOLIB_FILES} ${SSYSTEM_FILES} ${JSYSTEM_FILES} ${REL_FILES} ${DUSK_FILES} ${DOLPHIN_FILES} - src/dusk/imgui/ImGuiStubLog.cpp) + src/dusk/imgui/ImGuiStubLog.cpp + src/dusk/imgui/ImGuiAudio.cpp) target_link_libraries(game PRIVATE game_debug cxxopts::cxxopts) target_compile_definitions(game PRIVATE TARGET_PC AVOID_UB=1 VERSION=0 NDEBUG=1 NDEBUG_DEFINED=1 DEBUG_DEFINED=0 diff --git a/files.cmake b/files.cmake index 1302f3c71f..8504aecb95 100644 --- a/files.cmake +++ b/files.cmake @@ -507,10 +507,6 @@ set(JSYSTEM_DEBUG_FILES libs/JSystem/src/JAudio2/JASDSPInterface.cpp libs/JSystem/src/JAudio2/JASDriverIF.cpp libs/JSystem/src/JAudio2/JASSoundParams.cpp - libs/JSystem/src/JAudio2/dspproc.cpp - libs/JSystem/src/JAudio2/dsptask.cpp - libs/JSystem/src/JAudio2/osdsp.cpp - libs/JSystem/src/JAudio2/osdsp_task.cpp libs/JSystem/src/JAudio2/JAIAudible.cpp libs/JSystem/src/JAudio2/JAIAudience.cpp libs/JSystem/src/JAudio2/JAISe.cpp diff --git a/include/Z2AudioLib/Z2DebugSys.h b/include/Z2AudioLib/Z2DebugSys.h index 694086a469..80cadc7a85 100644 --- a/include/Z2AudioLib/Z2DebugSys.h +++ b/include/Z2AudioLib/Z2DebugSys.h @@ -26,7 +26,7 @@ public: virtual ~Z2HioSeSeqDataMgr() {} virtual SeqDataReturnValue getSeqData(JAISoundID param_1, JAISeqData* param_2) { if (field_0x18->getSeqList()->getSeqData(param_1, param_2)) { - param_2->field_0x4 = 4; + param_2->mOffset = 4; return SeqDataReturnValue_2; } else { return JAUSeqDataMgr_SeqCollection::getSeqData(param_1, param_2); diff --git a/include/Z2AudioLib/Z2SoundHandles.h b/include/Z2AudioLib/Z2SoundHandles.h index 2d9d490f5e..5915e5967b 100644 --- a/include/Z2AudioLib/Z2SoundHandles.h +++ b/include/Z2AudioLib/Z2SoundHandles.h @@ -22,7 +22,7 @@ public: bool isActive() const; Z2SoundHandlePool* getHandleSoundID(JAISoundID soundID); - Z2SoundHandlePool* getHandleUserData(u32 userData); + Z2SoundHandlePool* getHandleUserData(uintptr_t userData); void stopAllSounds(u32 fadeTime); diff --git a/include/dusk/audio.h b/include/dusk/audio.h index 46a2dd8859..e3dfda9f52 100644 --- a/include/dusk/audio.h +++ b/include/dusk/audio.h @@ -2,13 +2,13 @@ #define DUSK_AUDIO_H #if TARGET_PC -#define DUSK_AUDIO_DISABLED 1 +#define DUSK_AUDIO_DISABLED 0 #else #define DUSK_AUDIO_DISABLED 0 #endif #if TARGET_PC -#define DUSK_AUDIO_SKIP(...) return __VA_ARGS__; +#define DUSK_AUDIO_SKIP(...) #else #define DUSK_AUDIO_SKIP(...) #endif diff --git a/include/dusk/audio/DuskAudioSystem.h b/include/dusk/audio/DuskAudioSystem.h new file mode 100644 index 0000000000..1b31db6e7c --- /dev/null +++ b/include/dusk/audio/DuskAudioSystem.h @@ -0,0 +1,16 @@ +#pragma once + +#include + +namespace dusk::audio { + /** + * Initialize the audio system and start playing audio. + */ + void Initialize(); + + void SetMasterVolume(f32 value); + + u32 GetResetCount(int channelIdx); + + f32 VolumeFromU16(u16 value); +} diff --git a/include/dusk/main.h b/include/dusk/main.h new file mode 100644 index 0000000000..b357de8ea5 --- /dev/null +++ b/include/dusk/main.h @@ -0,0 +1,8 @@ +#ifndef DUSK_MAIN_H +#define DUSK_MAIN_H + +namespace dusk { + extern bool IsShuttingDown; +} + +#endif // DUSK_MAIN_H diff --git a/include/dusk/os.h b/include/dusk/os.h new file mode 100644 index 0000000000..180bdb9b1a --- /dev/null +++ b/include/dusk/os.h @@ -0,0 +1,14 @@ +#ifndef DUSK_OS_H +#define DUSK_OS_H + +#ifdef __cplusplus +extern "C" { +#endif + +void OSSetCurrentThreadName(const char* name); + +#ifdef __cplusplus +} +#endif + +#endif // DUSK_OS_H \ No newline at end of file diff --git a/include/dusk/string.hpp b/include/dusk/string.hpp new file mode 100644 index 0000000000..7de1b1ad75 --- /dev/null +++ b/include/dusk/string.hpp @@ -0,0 +1,58 @@ +#ifndef DUSK_STRING_HPP +#define DUSK_STRING_HPP + +#include "global.h" +#include +#include + +namespace dusk { + +inline void strncpyProxy(char* dst, const char* src, size_t count) { +#if _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4996) +#endif + strncpy(dst, src, count); +#if _MSC_VER +#pragma warning(pop) +#endif +} + +/** + * Copy a string to a fixed-size array. + * Truncates if the destination is not large enough, always inserts a null terminator (padding the remainder of the buffer with zeroes.) + */ +template +void SafeStringCopyTruncate(char (&buffer)[BufSize], const char* src) { + static_assert(BufSize > 0, "Target buffer cannot be size zero"); + + if (buffer == src) { + CRASH("Cannot copy string to same buffer"); + } + + strncpyProxy(buffer, src, BufSize); + buffer[BufSize - 1] = 0; +} + +/** + * Copy a string to a fixed-size array. + * Aborts if the destination is not large enough, always inserts a null terminator (padding the remainder of the buffer with zeroes.) + */ +template +void SafeStringCopy(char (&buffer)[BufSize], const char* src) { + static_assert(BufSize > 0, "Target buffer cannot be size zero"); + if (buffer == src) { + CRASH("Cannot copy string to same buffer"); + } + + if (strlen(src) > BufSize - 1) { + CRASH("Destination buffer too small!"); + } + + strncpyProxy(buffer, src, BufSize); + buffer[BufSize - 1] = 0; +} + +} + +#endif // DUSK_STRING_HPP diff --git a/include/f_pc/f_pc_manager.h b/include/f_pc/f_pc_manager.h index f772949d85..d8d9cbe1c9 100644 --- a/include/f_pc/f_pc_manager.h +++ b/include/f_pc/f_pc_manager.h @@ -9,7 +9,11 @@ #include "f_pc/f_pc_stdcreate_req.h" #include "f_pc/f_pc_searcher.h" +#if TARGET_PC +enum : u32 { +#else enum { +#endif fpcM_UNK_PROCESS_ID_e = 0xFFFFFFFE, fpcM_ERROR_PROCESS_ID_e = 0xFFFFFFFF, }; diff --git a/include/global.h b/include/global.h index e6291778d4..3720586ae3 100644 --- a/include/global.h +++ b/include/global.h @@ -83,7 +83,11 @@ extern int __abs(int); void* __memcpy(void*, const void*, int); #endif -#ifdef _MSVC_LANG +#ifndef M_PI +#define M_PI 3.14159265358979323846f +#endif + +#if defined(_MSVC_LANG) && !defined(__clang__) inline int __builtin_clz(unsigned int v) { int count = 32; while (v != 0) { @@ -94,7 +98,6 @@ inline int __builtin_clz(unsigned int v) { } #define COMPOUND_LITERAL(x) -#define M_PI 3.14159265358979323846f #else #define COMPOUND_LITERAL(x) (x) @@ -215,4 +218,7 @@ using std::isnan; #define IS_REF_NONNULL(r) (1) #endif +#define CRASH(msg) OSPanic(__FILE__, __LINE__, "%s", msg) +#define CRASHF(msg, ...) OSPanic(__FILE__, __LINE__, msg, __VA_ARGS__) + #endif diff --git a/libs/JSystem/include/JSystem/J3DGraphAnimator/J3DAnimation.h b/libs/JSystem/include/JSystem/J3DGraphAnimator/J3DAnimation.h index c7c8730a44..3c5133e880 100644 --- a/libs/JSystem/include/JSystem/J3DGraphAnimator/J3DAnimation.h +++ b/libs/JSystem/include/JSystem/J3DGraphAnimator/J3DAnimation.h @@ -9,9 +9,9 @@ #include "dusk/endian.h" #if TARGET_PC -#define OFFSET_PTR BE(u32) +#define OFFSET_PTR_V0 BE(u32) #else -#define OFFSET_PTR void* +#define OFFSET_PTR_V0 void* #endif struct J3DTransformInfo; @@ -80,7 +80,7 @@ struct J3DAnmColorKeyTable { */ struct J3DAnmVtxColorIndexData { /* 0x00 */ BE(u16) mNum; - /* 0x04 */ OFFSET_PTR mpData; + /* 0x04 */ OFFSET_PTR_V0 mpData; }; /** @@ -200,13 +200,13 @@ struct J3DAnmVtxColorFullData { /* 0x0A */ BE(s16) mFrameMax; /* 0x0C */ BE(u16) mAnmTableNum[2]; /* 0x10 */ u8 field_0x10[0x18 - 0x10]; - /* 0x18 */ OFFSET_PTR mTableOffsets[2]; - /* 0x20 */ OFFSET_PTR mVtxColorIndexDataOffsets[2]; - /* 0x28 */ OFFSET_PTR mVtxColorIndexPointerOffsets[2]; - /* 0x30 */ OFFSET_PTR mRValuesOffset; - /* 0x34 */ OFFSET_PTR mGValuesOffset; - /* 0x38 */ OFFSET_PTR mBValuesOffset; - /* 0x3C */ OFFSET_PTR mAValuesOffset; + /* 0x18 */ OFFSET_PTR_V0 mTableOffsets[2]; + /* 0x20 */ OFFSET_PTR_V0 mVtxColorIndexDataOffsets[2]; + /* 0x28 */ OFFSET_PTR_V0 mVtxColorIndexPointerOffsets[2]; + /* 0x30 */ OFFSET_PTR_V0 mRValuesOffset; + /* 0x34 */ OFFSET_PTR_V0 mGValuesOffset; + /* 0x38 */ OFFSET_PTR_V0 mBValuesOffset; + /* 0x3C */ OFFSET_PTR_V0 mAValuesOffset; }; // Size = 0x40 STATIC_ASSERT(sizeof(J3DAnmVtxColorFullData) == 0x40); @@ -222,8 +222,8 @@ struct J3DAnmVisibilityFullData { /* 0x0A */ BE(s16) mFrameMax; /* 0x0C */ BE(u16) field_0xc; /* 0x0E */ BE(u16) field_0xe; - /* 0x10 */ OFFSET_PTR mTableOffset; - /* 0x14 */ OFFSET_PTR mValuesOffset; + /* 0x10 */ OFFSET_PTR_V0 mTableOffset; + /* 0x14 */ OFFSET_PTR_V0 mValuesOffset; }; // Size = 0x18 STATIC_ASSERT(sizeof(J3DAnmVisibilityFullData) == 0x18); @@ -239,10 +239,10 @@ struct J3DAnmTransformFullData { /* 0x0A */ BE(s16) mFrameMax; /* 0x0C */ BE(u16) field_0xc; /* 0x0E */ u8 field_0xe[0x14 - 0xe]; - /* 0x14 */ OFFSET_PTR mTableOffset; - /* 0x18 */ OFFSET_PTR mScaleValOffset; - /* 0x1C */ OFFSET_PTR mRotValOffset; - /* 0x20 */ OFFSET_PTR mTransValOffset; + /* 0x14 */ OFFSET_PTR_V0 mTableOffset; + /* 0x18 */ OFFSET_PTR_V0 mScaleValOffset; + /* 0x1C */ OFFSET_PTR_V0 mRotValOffset; + /* 0x20 */ OFFSET_PTR_V0 mTransValOffset; }; // Size = 0x24 STATIC_ASSERT(sizeof(J3DAnmTransformFullData) == 0x24); @@ -261,13 +261,13 @@ struct J3DAnmColorKeyData { /* 0x12 */ BE(u16) field_0x12; /* 0x14 */ BE(u16) field_0x14; /* 0x16 */ BE(u16) field_0x16; - /* 0x18 */ OFFSET_PTR mTableOffset; - /* 0x1C */ OFFSET_PTR mUpdateMaterialIDOffset; - /* 0x20 */ OFFSET_PTR mNameTabOffset; - /* 0x24 */ OFFSET_PTR mRValOffset; - /* 0x28 */ OFFSET_PTR mGValOffset; - /* 0x2C */ OFFSET_PTR mBValOffset; - /* 0x30 */ OFFSET_PTR mAValOffset; + /* 0x18 */ OFFSET_PTR_V0 mTableOffset; + /* 0x1C */ OFFSET_PTR_V0 mUpdateMaterialIDOffset; + /* 0x20 */ OFFSET_PTR_V0 mNameTabOffset; + /* 0x24 */ OFFSET_PTR_V0 mRValOffset; + /* 0x28 */ OFFSET_PTR_V0 mGValOffset; + /* 0x2C */ OFFSET_PTR_V0 mBValOffset; + /* 0x30 */ OFFSET_PTR_V0 mAValOffset; }; // Size = 0x34 STATIC_ASSERT(sizeof(J3DAnmColorKeyData) == 0x34); @@ -285,26 +285,26 @@ struct J3DAnmTextureSRTKeyData { /* 0x0E */ BE(u16) field_0xe; /* 0x10 */ BE(u16) field_0x10; /* 0x12 */ BE(u16) field_0x12; - /* 0x14 */ OFFSET_PTR mTableOffset; - /* 0x18 */ OFFSET_PTR mUpdateMatIDOffset; - /* 0x1C */ OFFSET_PTR mNameTab1Offset; - /* 0x20 */ OFFSET_PTR mUpdateTexMtxIDOffset; - /* 0x24 */ OFFSET_PTR unkOffset; - /* 0x28 */ OFFSET_PTR mScaleValOffset; - /* 0x2C */ OFFSET_PTR mRotValOffset; - /* 0x30 */ OFFSET_PTR mTransValOffset; + /* 0x14 */ OFFSET_PTR_V0 mTableOffset; + /* 0x18 */ OFFSET_PTR_V0 mUpdateMatIDOffset; + /* 0x1C */ OFFSET_PTR_V0 mNameTab1Offset; + /* 0x20 */ OFFSET_PTR_V0 mUpdateTexMtxIDOffset; + /* 0x24 */ OFFSET_PTR_V0 unkOffset; + /* 0x28 */ OFFSET_PTR_V0 mScaleValOffset; + /* 0x2C */ OFFSET_PTR_V0 mRotValOffset; + /* 0x30 */ OFFSET_PTR_V0 mTransValOffset; /* 0x34 */ BE(u16) field_0x34; /* 0x36 */ BE(u16) field_0x36; /* 0x38 */ BE(u16) field_0x38; /* 0x3A */ BE(u16) field_0x3a; - /* 0x3C */ OFFSET_PTR mInfoTable2Offset; - /* 0x40 */ OFFSET_PTR field_0x40; - /* 0x44 */ OFFSET_PTR mNameTab2Offset; - /* 0x48 */ OFFSET_PTR field_0x48; - /* 0x4C */ OFFSET_PTR field_0x4c; - /* 0x50 */ OFFSET_PTR field_0x50; - /* 0x54 */ OFFSET_PTR field_0x54; - /* 0x58 */ OFFSET_PTR field_0x58; + /* 0x3C */ OFFSET_PTR_V0 mInfoTable2Offset; + /* 0x40 */ OFFSET_PTR_V0 field_0x40; + /* 0x44 */ OFFSET_PTR_V0 mNameTab2Offset; + /* 0x48 */ OFFSET_PTR_V0 field_0x48; + /* 0x4C */ OFFSET_PTR_V0 field_0x4c; + /* 0x50 */ OFFSET_PTR_V0 field_0x50; + /* 0x54 */ OFFSET_PTR_V0 field_0x54; + /* 0x58 */ OFFSET_PTR_V0 field_0x58; /* 0x5C */ BE(s32) field_0x5c; }; // Size = 0x60 @@ -321,13 +321,13 @@ struct J3DAnmVtxColorKeyData { /* 0x0A */ BE(s16) mFrameMax; /* 0x0C */ BE(u16) mAnmTableNum[2]; /* 0x10 */ u8 field_0x10[0x18 - 0x10]; - /* 0x18 */ OFFSET_PTR mTableOffsets[2]; - /* 0x20 */ OFFSET_PTR mVtxColoIndexDataOffset[2]; - /* 0x28 */ OFFSET_PTR mVtxColoIndexPointerOffset[2]; - /* 0x30 */ OFFSET_PTR mRValOffset; - /* 0x34 */ OFFSET_PTR mGValOffset; - /* 0x38 */ OFFSET_PTR mBValOffset; - /* 0x3C */ OFFSET_PTR mAValOffset; + /* 0x18 */ OFFSET_PTR_V0 mTableOffsets[2]; + /* 0x20 */ OFFSET_PTR_V0 mVtxColoIndexDataOffset[2]; + /* 0x28 */ OFFSET_PTR_V0 mVtxColoIndexPointerOffset[2]; + /* 0x30 */ OFFSET_PTR_V0 mRValOffset; + /* 0x34 */ OFFSET_PTR_V0 mGValOffset; + /* 0x38 */ OFFSET_PTR_V0 mBValOffset; + /* 0x3C */ OFFSET_PTR_V0 mAValOffset; }; // Size = 0x40 STATIC_ASSERT(sizeof(J3DAnmVtxColorKeyData) == 0x40); @@ -343,10 +343,10 @@ struct J3DAnmTexPatternFullData { /* 0x0A */ BE(s16) mFrameMax; /* 0x0C */ BE(u16) field_0xc; /* 0x0E */ BE(u16) field_0xe; - /* 0x10 */ OFFSET_PTR mTableOffset; - /* 0x14 */ OFFSET_PTR mValuesOffset; - /* 0x18 */ OFFSET_PTR mUpdateMaterialIDOffset; - /* 0x1C */ OFFSET_PTR mNameTabOffset; + /* 0x10 */ OFFSET_PTR_V0 mTableOffset; + /* 0x14 */ OFFSET_PTR_V0 mValuesOffset; + /* 0x18 */ OFFSET_PTR_V0 mUpdateMaterialIDOffset; + /* 0x1C */ OFFSET_PTR_V0 mNameTabOffset; }; // Size = 0x20 STATIC_ASSERT(sizeof(J3DAnmTexPatternFullData) == 0x20); @@ -370,20 +370,20 @@ struct J3DAnmTevRegKeyData { /* 0x1A */ BE(u16) field_0x1a; /* 0x1C */ BE(u16) field_0x1c; /* 0x1E */ BE(u16) field_0x1e; - /* 0x20 */ OFFSET_PTR mCRegTableOffset; - /* 0x24 */ OFFSET_PTR mKRegTableOffset; - /* 0x28 */ OFFSET_PTR mCRegUpdateMaterialIDOffset; - /* 0x2C */ OFFSET_PTR mKRegUpdateMaterialIDOffset; - /* 0x30 */ OFFSET_PTR mCRegNameTabOffset; - /* 0x34 */ OFFSET_PTR mKRegNameTabOffset; - /* 0x38 */ OFFSET_PTR mCRValuesOffset; - /* 0x3C */ OFFSET_PTR mCGValuesOffset; - /* 0x40 */ OFFSET_PTR mCBValuesOffset; - /* 0x44 */ OFFSET_PTR mCAValuesOffset; - /* 0x48 */ OFFSET_PTR mKRValuesOffset; - /* 0x4C */ OFFSET_PTR mKGValuesOffset; - /* 0x50 */ OFFSET_PTR mKBValuesOffset; - /* 0x54 */ OFFSET_PTR mKAValuesOffset; + /* 0x20 */ OFFSET_PTR_V0 mCRegTableOffset; + /* 0x24 */ OFFSET_PTR_V0 mKRegTableOffset; + /* 0x28 */ OFFSET_PTR_V0 mCRegUpdateMaterialIDOffset; + /* 0x2C */ OFFSET_PTR_V0 mKRegUpdateMaterialIDOffset; + /* 0x30 */ OFFSET_PTR_V0 mCRegNameTabOffset; + /* 0x34 */ OFFSET_PTR_V0 mKRegNameTabOffset; + /* 0x38 */ OFFSET_PTR_V0 mCRValuesOffset; + /* 0x3C */ OFFSET_PTR_V0 mCGValuesOffset; + /* 0x40 */ OFFSET_PTR_V0 mCBValuesOffset; + /* 0x44 */ OFFSET_PTR_V0 mCAValuesOffset; + /* 0x48 */ OFFSET_PTR_V0 mKRValuesOffset; + /* 0x4C */ OFFSET_PTR_V0 mKGValuesOffset; + /* 0x50 */ OFFSET_PTR_V0 mKBValuesOffset; + /* 0x54 */ OFFSET_PTR_V0 mKAValuesOffset; }; // Size = 0x58 STATIC_ASSERT(sizeof(J3DAnmTevRegKeyData) == 0x58); @@ -399,13 +399,13 @@ struct J3DAnmColorFullData { /* PlaceHolder Structure */ /* 0x0C */ BE(s16) mFrameMax; /* 0x0E */ BE(u16) mUpdateMaterialNum; /* 0x10 */ u8 field_0x10[0x18 - 0x10]; - /* 0x18 */ OFFSET_PTR mTableOffset; - /* 0x1C */ OFFSET_PTR mUpdateMaterialIDOffset; - /* 0x20 */ OFFSET_PTR mNameTabOffset; - /* 0x24 */ OFFSET_PTR mRValuesOffset; - /* 0x28 */ OFFSET_PTR mGValuesOffset; - /* 0x2C */ OFFSET_PTR mBValuesOffset; - /* 0x30 */ OFFSET_PTR mAValuesOffset; + /* 0x18 */ OFFSET_PTR_V0 mTableOffset; + /* 0x1C */ OFFSET_PTR_V0 mUpdateMaterialIDOffset; + /* 0x20 */ OFFSET_PTR_V0 mNameTabOffset; + /* 0x24 */ OFFSET_PTR_V0 mRValuesOffset; + /* 0x28 */ OFFSET_PTR_V0 mGValuesOffset; + /* 0x2C */ OFFSET_PTR_V0 mBValuesOffset; + /* 0x30 */ OFFSET_PTR_V0 mAValuesOffset; }; // Size = 0x34 STATIC_ASSERT(sizeof(J3DAnmColorFullData) == 0x34); @@ -431,10 +431,10 @@ struct J3DAnmTransformKeyData { /* 0x0E */ BE(u16) mSCount; /* 0x10 */ BE(u16) mRCount; /* 0x12 */ BE(u16) mTCount; - /* 0x14 */ OFFSET_PTR mJointAnimationTableOffs; - /* 0x18 */ OFFSET_PTR mSTableOffs; - /* 0x1c */ OFFSET_PTR mRTableOffs; - /* 0x20 */ OFFSET_PTR mTTableOffs; + /* 0x14 */ OFFSET_PTR_V0 mJointAnimationTableOffs; + /* 0x18 */ OFFSET_PTR_V0 mSTableOffs; + /* 0x1c */ OFFSET_PTR_V0 mRTableOffs; + /* 0x20 */ OFFSET_PTR_V0 mTTableOffs; }; /** @@ -446,8 +446,8 @@ struct J3DAnmClusterKeyData { /* 0x08 */ u8 field_0x8; /* 0x0A */ BE(s16) mFrameMax; /* 0x0C */ BE(s32) field_0xc; - /* 0x10 */ OFFSET_PTR mTableOffset; - /* 0x14 */ OFFSET_PTR mWeightOffset; + /* 0x10 */ OFFSET_PTR_V0 mTableOffset; + /* 0x14 */ OFFSET_PTR_V0 mWeightOffset; }; /** @@ -459,8 +459,8 @@ struct J3DAnmClusterFullData { /* 0x08 */ u8 field_0x8; /* 0x0A */ BE(s16) mFrameMax; /* 0x0C */ BE(s32) field_0xc; - /* 0x10 */ OFFSET_PTR mTableOffset; - /* 0x14 */ OFFSET_PTR mWeightOffset; + /* 0x10 */ OFFSET_PTR_V0 mTableOffset; + /* 0x14 */ OFFSET_PTR_V0 mWeightOffset; }; /** @@ -718,7 +718,7 @@ public: // Address to which getAnmVtxColorIndexData pointers are relative. u16* colorAddressBase[2]; - u16* offsetColorIndexAddress(u8 index, OFFSET_PTR ptr) const { + u16* offsetColorIndexAddress(u8 index, OFFSET_PTR_V0 ptr) const { return colorAddressBase[index] + ptr; } #endif @@ -994,6 +994,6 @@ public: /* 0x10 */ f32 mFrame; }; // Size: 0x14 -#undef OFFSET_PTR +#undef OFFSET_PTR_V0 #endif /* J3DANIMATION_H */ diff --git a/libs/JSystem/include/JSystem/J3DGraphAnimator/J3DCluster.h b/libs/JSystem/include/JSystem/J3DGraphAnimator/J3DCluster.h index 3cbb6f195d..2a71ada3dd 100644 --- a/libs/JSystem/include/JSystem/J3DGraphAnimator/J3DCluster.h +++ b/libs/JSystem/include/JSystem/J3DGraphAnimator/J3DCluster.h @@ -14,9 +14,9 @@ class J3DAnmCluster; class JUTNameTab; #if TARGET_PC -#define OFFSET_PTR BE(u32) +#define OFFSET_PTR_V0 BE(u32) #else -#define OFFSET_PTR void* +#define OFFSET_PTR_V0 void* #endif /** @@ -49,7 +49,7 @@ public: /* 0x00 */ BE(f32) mMaxAngle; /* 0x04 */ BE(f32) mMinAngle; - /* 0x08 */ OFFSET_PTR mClusterKey; + /* 0x08 */ OFFSET_PTR_V0 mClusterKey; /* 0x0C */ u8 mFlags; /* 0x0E */ u8 field_0xe[0x10 - 0xD]; /* 0x10 */ BE(u16) mKeyNum; @@ -57,9 +57,9 @@ public: /* 0x14 */ BE(u16) field_0x14; /* 0x16 */ BE(u16) field_0x16; #if TARGET_PC - OFFSET_PTR field_0x18; - OFFSET_PTR mClusterVertex; - OFFSET_PTR mDeformer; + OFFSET_PTR_V0 field_0x18; + OFFSET_PTR_V0 mClusterVertex; + OFFSET_PTR_V0 mDeformer; #else /* 0x18 */ u16* field_0x18; /* 0x1C */ J3DClusterVertex* mClusterVertex; @@ -82,8 +82,8 @@ public: /* 0x00 */ BE(u16) mPosNum; /* 0x02 */ BE(u16) mNrmNum; - /* 0x04 */ OFFSET_PTR field_0x4; - /* 0x08 */ OFFSET_PTR field_0x8; + /* 0x04 */ OFFSET_PTR_V0 field_0x4; + /* 0x08 */ OFFSET_PTR_V0 field_0x8; }; // Size: 0x0C /** @@ -144,14 +144,14 @@ public: /* 0x00 */ BE(u16) mNum; #if TARGET_PC - /* 0x04 */ OFFSET_PTR field_0x4; - /* 0x08 */ OFFSET_PTR field_0x8; + /* 0x04 */ OFFSET_PTR_V0 field_0x4; + /* 0x08 */ OFFSET_PTR_V0 field_0x8; #else /* 0x04 */ u16* field_0x4; /* 0x08 */ u16* field_0x8; #endif }; // Size: 0x0C -#undef OFFSET_PTR +#undef OFFSET_PTR_V0 #endif /* J3DCLUSTER_H */ diff --git a/libs/JSystem/include/JSystem/J3DGraphLoader/J3DClusterLoader.h b/libs/JSystem/include/JSystem/J3DGraphLoader/J3DClusterLoader.h index 8fa2681f35..2899065150 100644 --- a/libs/JSystem/include/JSystem/J3DGraphLoader/J3DClusterLoader.h +++ b/libs/JSystem/include/JSystem/J3DGraphLoader/J3DClusterLoader.h @@ -7,9 +7,9 @@ #include "dusk/endian.h" #if TARGET_PC -#define OFFSET_PTR BE(u32) +#define OFFSET_PTR_V0 BE(u32) #else -#define OFFSET_PTR void* +#define OFFSET_PTR_V0 void* #endif /** @@ -31,13 +31,13 @@ public: /* 0x0C */ BE(u16) mClusterVertexNum; /* 0x0E */ BE(u16) mVtxPosNum; /* 0x10 */ BE(u16) mVtxNrmNum; - /* 0x14 */ OFFSET_PTR mClusterPointer; - /* 0x18 */ OFFSET_PTR mClusterKeyPointer; - /* 0x1C */ OFFSET_PTR mClusterVertex; - /* 0x20 */ OFFSET_PTR mVtxPos; - /* 0x24 */ OFFSET_PTR mVtxNrm; - /* 0x28 */ OFFSET_PTR mClusterName; - /* 0x2C */ OFFSET_PTR mClusterKeyName; + /* 0x14 */ OFFSET_PTR_V0 mClusterPointer; + /* 0x18 */ OFFSET_PTR_V0 mClusterKeyPointer; + /* 0x1C */ OFFSET_PTR_V0 mClusterVertex; + /* 0x20 */ OFFSET_PTR_V0 mVtxPos; + /* 0x24 */ OFFSET_PTR_V0 mVtxNrm; + /* 0x28 */ OFFSET_PTR_V0 mClusterName; + /* 0x2C */ OFFSET_PTR_V0 mClusterKeyName; }; /** @@ -67,6 +67,6 @@ public: /* 0x04 */ J3DDeformData* mpDeformData; }; -#undef OFFSET_PTR +#undef OFFSET_PTR_V0 #endif /* J3DCLUSTERLOADER_H */ diff --git a/libs/JSystem/include/JSystem/JAudio2/JAISeqDataMgr.h b/libs/JSystem/include/JSystem/JAudio2/JAISeqDataMgr.h index 510f1f4905..a517a58c16 100644 --- a/libs/JSystem/include/JSystem/JAudio2/JAISeqDataMgr.h +++ b/libs/JSystem/include/JSystem/JAudio2/JAISeqDataMgr.h @@ -10,17 +10,17 @@ */ struct JAISeqData { JAISeqData(const void* param_0, u32 param_1) { - field_0x0 = (void*)param_0; - field_0x4 = param_1; + mBase = (void*)param_0; + mOffset = param_1; } void set(const void* param_0, u32 param_1) { - field_0x0 = (void*)param_0; - field_0x4 = param_1; + mBase = (void*)param_0; + mOffset = param_1; } - /* 0x00 */ void* field_0x0; - /* 0x04 */ u32 field_0x4; + /* 0x00 */ void* mBase; + /* 0x04 */ u32 mOffset; }; /** @@ -29,10 +29,10 @@ struct JAISeqData { */ struct JAISeqDataRegion { bool intersects(const JAISeqData& seqData) const { - if ((uintptr_t)addr + size < (uintptr_t)seqData.field_0x0) { + if ((uintptr_t)addr + size < (uintptr_t)seqData.mBase) { return false; } - if ((uintptr_t)seqData.field_0x0 + seqData.field_0x4 < (uintptr_t)addr) { + if ((uintptr_t)seqData.mBase + seqData.mOffset < (uintptr_t)addr) { return false; } return true; diff --git a/libs/JSystem/include/JSystem/JAudio2/JAISound.h b/libs/JSystem/include/JSystem/JAudio2/JAISound.h index 5e1cd40b4b..155eca1e65 100644 --- a/libs/JSystem/include/JSystem/JAudio2/JAISound.h +++ b/libs/JSystem/include/JSystem/JAudio2/JAISound.h @@ -5,6 +5,7 @@ #include "JSystem/JAudio2/JAIAudible.h" #include "JSystem/JUtility/JUTAssert.h" #include "global.h" +#include "dusk/endian.h" #include class JAISound; @@ -55,16 +56,16 @@ public: void setAnonymous() { id_.composite_ = -1; } union { - u32 composite_; + BE(u32) composite_; struct { union { - u16 value; + BE(u16) value; struct { u8 sectionID; u8 groupID; } parts; } type; - u16 waveID; + BE(u16) waveID; } info; } id_; }; diff --git a/libs/JSystem/include/JSystem/JAudio2/JASAramStream.h b/libs/JSystem/include/JSystem/JAudio2/JASAramStream.h index 17d4c6f521..dcfcebd30a 100644 --- a/libs/JSystem/include/JSystem/JAudio2/JASAramStream.h +++ b/libs/JSystem/include/JSystem/JAudio2/JASAramStream.h @@ -4,6 +4,7 @@ #include "JSystem/JAudio2/JASTaskThread.h" #include "JSystem/JUtility/JUTAssert.h" #include +#include "dusk/endian.h" class JASChannel; @@ -11,12 +12,17 @@ namespace JASDsp { struct TChannel; } +#define STREAM_FORMAT_ADPCM4 0 +#define STREAM_FORMAT_PCM16 1 + /** * @ingroup jsystem-jaudio - * + * Plays streamed music from DVD .ast files. */ class JASAramStream { public: + static const int CHANNEL_MAX = 6; + typedef void (*StreamCallback)(u32, JASAramStream*, void*); enum CallbackType { @@ -27,34 +33,40 @@ public: // Used internally for passing data to task functions struct TaskData { /* 0x0 */ JASAramStream* stream; - /* 0x4 */ u32 field_0x4; - /* 0x8 */ int field_0x8; + /* 0x4 */ u32 param0; + /* 0x8 */ int param1; }; struct Header { - /* 0x00 */ u32 tag; + /* 0x00 */ BE(u32) tag; // 'STRM' +#if TARGET_PC + /* 0x04 */ BE(u32) soundBlockSize; + /* 0x08 */ BE(u16) format; + /* 0x0A */ BE(u16) bits; +#else /* 0x04 */ u8 field_0x4[5]; /* 0x09 */ u8 format; /* 0x0A */ u8 bits; - /* 0x0C */ u16 channels; - /* 0x0E */ u16 loop; - /* 0x10 */ int field_0x10; - /* 0x14 */ u8 field_0x14[4]; - /* 0x18 */ int loop_start; - /* 0x1C */ int loop_end; - /* 0x20 */ u32 block_size; - /* 0x24 */ u8 field_0x24[4]; - /* 0x28 */ u8 field_0x28; - /* 0x29 */ u8 field_0x29[0x17]; +#endif + /* 0x0C */ BE(u16) channels; + /* 0x0E */ BE(u16) loop; + /* 0x10 */ BE(int) mSampleRate; + /* 0x14 */ BE(u32) mSampleCount; // unused + /* 0x18 */ BE(int) loop_start; + /* 0x1C */ BE(int) loop_end; + /* 0x20 */ BE(u32) block_size; + /* 0x24 */ u8 _unused2[4]; + /* 0x28 */ u8 mVolume; + /* 0x29 */ u8 _unused3[0x17]; }; // Size: 0x40 struct BlockHeader { - /* 0x00 */ u32 tag; - /* 0x04 */ u32 field_0x4; + /* 0x00 */ BE(u32) tag; // 'BLCK' + /* 0x04 */ BE(u32) mSize; /* 0x08 */ struct { - s16 field_0x0; - s16 field_0x2; - } field_0x8[6]; + BE(s16) mpLast; + BE(s16) mpPenult; + } mAdpcmContinuationData[CHANNEL_MAX]; }; // Size: 0x20 static void initSystem(u32, u32); @@ -65,6 +77,10 @@ public: bool stop(u16); bool pause(bool); bool cancel(); + + /** + * Calculate the amount of (decoded) audio samples in a single block of streamed audio. + */ u32 getBlockSamples() const; static void headerLoadTask(void*); static void firstLoadTask(void*); @@ -128,46 +144,103 @@ public: static u32 getBlockSize() { return sBlockSize; } - static const int CHANNEL_MAX = 6; + /** + * Queue used to send specific commands that will be processed on the audio thread. + * These commands are sent from the main thread. + */ + /* 0x000 */ OSMessageQueue mMainCommandQueue; - /* 0x000 */ OSMessageQueue field_0x000; - /* 0x020 */ OSMessageQueue field_0x020; - /* 0x040 */ void* field_0x040[16]; - /* 0x080 */ void* field_0x080[4]; + /** + * Queue used to send specific commands that will be processed on the audio thread. + * These commands are sent from the load (DVD) thread. + */ + /* 0x020 */ OSMessageQueue mLoadCommandQueue; + + /** + * Backing message storage for mMainCommandQueue. + */ + /* 0x040 */ void* mMainCommandQueueArray[16]; + + /** + * Backing message storage for mLoadCommandQueue. + */ + /* 0x080 */ void* mLoadCommandQueueArray[4]; /* 0x090 */ JASChannel* mChannels[CHANNEL_MAX]; - /* 0x0A8 */ JASChannel* field_0x0a8; - /* 0x0AC */ bool field_0x0ac; - /* 0x0AD */ bool field_0x0ad; - /* 0x0AE */ u8 field_0x0ae; + + /** + * The first audio channel initialized among mChannels. + * Used for the majority of bookkeeping, other channels replicate its state. + */ + /* 0x0A8 */ JASChannel* mPrimaryChannel; + + /** + * If true, stream has finished preparing (reading headers and initial blocks), + * and is ready to play. + */ + /* 0x0AC */ bool mPrepareFinished; + /* 0x0AD */ bool mLoopEndLoaded; + + /** + * Bitflag containing pause reasons/state for the stream. + */ + /* 0x0AE */ u8 mPauseFlags; /* 0x0B0 */ int field_0x0b0; - /* 0x0B4 */ int field_0x0b4; - /* 0x0B8 */ u32 field_0x0b8; + + /** + * (adjusted) value of mSamplesLeft on the primary channel last subframe. + * Used to calculate how many samples have been read and determine when the DSP looped. + */ + /* 0x0B4 */ int mLastSamplesLeft; + + /** + * How many (decoded) samples the DSP has read so far. + */ + /* 0x0B8 */ u32 mReadSample; /* 0x0BC */ int field_0x0bc; - /* 0x0C0 */ bool field_0x0c0; + + /** + * If true, the current end (of loop, or just finish) is very close. + * Loop start/end positions are modified while this is set to account for this. + */ + /* 0x0C0 */ bool mEndSetup; /* 0x0C4 */ volatile u32 field_0x0c4; /* 0x0C8 */ volatile f32 field_0x0c8; /* 0x0CC */ DVDFileInfo mDvdFileInfo; - /* 0x108 */ u32 field_0x108; - /* 0x10C */ int field_0x10c; + /* 0x108 */ u32 mRingEndIndex; + + /** + * Index into the ARAM ring buffer that is currently being loaded. + * Wrapped around when incremented. + */ + /* 0x10C */ int mBlockRingIndex; + + /** + * Block currently being loaded. + */ /* 0x110 */ u32 mBlock; - /* 0x114 */ u8 field_0x114; - /* 0x118 */ u32 field_0x118; - /* 0x11C */ int field_0x11c; - /* 0x120 */ int field_0x120; - /* 0x124 */ int field_0x124; - /* 0x128 */ u16 field_0x128; - /* 0x12C */ int field_0x12c; - /* 0x130 */ s16 field_0x130[CHANNEL_MAX]; - /* 0x13C */ s16 field_0x13c[CHANNEL_MAX]; - /* 0x148 */ int field_0x148; - /* 0x14C */ u32 field_0x14c; + /* 0x114 */ u8 mIsCancelled; + /* 0x118 */ u32 mPendingLoadTasks; + /* 0x11C */ int mUpdateSamplesLeft; + /* 0x120 */ int mUpdateLoopStartSample; + /* 0x124 */ int mUpdateEndSample; + /* 0x128 */ u16 mUpdateLoopFlag; + + /** + * Bitflags updated in the play callback to track what data needs to be synchronized + * between all channels. + */ + /* 0x12C */ int mChannelUpdateFlags; + /* 0x130 */ s16 mpLasts[CHANNEL_MAX]; + /* 0x13C */ s16 mpPenults[CHANNEL_MAX]; + /* 0x148 */ int mAramAddress; + /* 0x14C */ u32 mAramSize; /* 0x150 */ StreamCallback mCallback; /* 0x154 */ void* mCallbackData; - /* 0x158 */ u16 field_0x158; + /* 0x158 */ u16 mFormat; /* 0x15A */ u16 mChannelNum; /* 0x15C */ u32 mBufCount; - /* 0x160 */ u32 field_0x160; - /* 0x164 */ u32 field_0x164; + /* 0x160 */ u32 mAramBlocksPerChannel; + /* 0x164 */ u32 mSampleRate; /* 0x168 */ bool mLoop; /* 0x16C */ u32 mLoopStart; /* 0x170 */ u32 mLoopEnd; @@ -177,11 +250,29 @@ public: /* 0x194 */ f32 mChannelPan[CHANNEL_MAX]; /* 0x1AC */ f32 mChannelFxMix[CHANNEL_MAX]; /* 0x1C4 */ f32 mChannelDolby[CHANNEL_MAX]; - /* 0x1DC */ u16 field_0x1dc[CHANNEL_MAX]; + /* 0x1DC */ u16 mMixConfig[CHANNEL_MAX]; + /** + * Thread that will be sent DVD load commands. + * This is the JASDvd thread in practice. + */ static JASTaskThread* sLoadThread; + + /** + * Buffer used to read DVD data. Can store the size of an entire streamed audio block. + */ static u8* sReadBuffer; + + /** + * Block size used by all streamed music in the game. + * This is 0x2760 for TP. + */ static u32 sBlockSize; + + /** + * Maximum amount of output channels for all streamed music in the game. + * This is 2 for TP (stereo). + */ static u32 sChannelMax; }; diff --git a/libs/JSystem/include/JSystem/JAudio2/JASAudioThread.h b/libs/JSystem/include/JSystem/JAudio2/JASAudioThread.h index 6be7d07000..dd9fed2183 100644 --- a/libs/JSystem/include/JSystem/JAudio2/JASAudioThread.h +++ b/libs/JSystem/include/JSystem/JAudio2/JASAudioThread.h @@ -32,11 +32,6 @@ struct JASAudioThread : public JKRThread, public JASGlobalInstance mInstOffset[0x80]; /* 0x204 */ u8 field_0x204[0x190]; /* 0x394 */ TOffset mPercOffset[12]; diff --git a/libs/JSystem/include/JSystem/JAudio2/JASCalc.h b/libs/JSystem/include/JSystem/JAudio2/JASCalc.h index bb8054675f..35b8fd5516 100644 --- a/libs/JSystem/include/JSystem/JAudio2/JASCalc.h +++ b/libs/JSystem/include/JSystem/JAudio2/JASCalc.h @@ -33,7 +33,11 @@ struct JASCalc { f32 fake2(s32 x); f32 fake3(); +#if AVOID_UB + static const s16 CUTOFF_TO_IIR_TABLE[129][4]; +#else static const s16 CUTOFF_TO_IIR_TABLE[128][4]; +#endif }; template diff --git a/libs/JSystem/include/JSystem/JAudio2/JASChannel.h b/libs/JSystem/include/JSystem/JAudio2/JASChannel.h index 042e3343cd..ce9b0b20de 100644 --- a/libs/JSystem/include/JSystem/JAudio2/JASChannel.h +++ b/libs/JSystem/include/JSystem/JAudio2/JASChannel.h @@ -6,6 +6,7 @@ #include "JSystem/JAudio2/JASOscillator.h" #include "JSystem/JAudio2/JASSoundParams.h" #include "JSystem/JAudio2/JASWaveInfo.h" +#include "JSystem/JAudio2/JASDSPInterface.h" #include struct JASDSPChannel; @@ -45,6 +46,9 @@ public: /* 0x14 */ f32 mDolby; }; +#define CHANNEL_WAVE 0 +#define CHANNEL_OSCILLATOR 2 + /** * @ingroup jsystem-jaudio * @@ -52,7 +56,7 @@ public: class JASChannel : public JASPoolAllocObject_MultiThreaded { public: typedef void (*Callback)(u32, JASChannel*, JASDsp::TChannel*, void*); - static const int BUSOUT_CPUCH = 6; + static const int BUSOUT_CPUCH = DSP_OUTPUT_CHANNELS; static const int OSC_NUM = 2; enum CallbackType { @@ -75,7 +79,7 @@ public: }; union MixConfig { - u16 whole; + BE(u16) whole; struct { u8 upper; u8 lower0 : 4; @@ -153,10 +157,14 @@ public: /* 0xD4 */ u32 mKeySweepCount; /* 0xD8 */ u32 mSkipSamples; struct { - u32 field_0x0; - JASWaveInfo field_0x4; + u32 mChannelType; // CHANNEL_WAVE or CHANNEL_OSCILLATOR + JASWaveInfo mWaveInfo; } field_0xdc; - intptr_t field_0x104; + union { + u32 mWaveAramAddress; + u32 mOscillatorSomething; + u32 field_0x104; + }; static OSMessageQueue sBankDisposeMsgQ; static OSMessage sBankDisposeMsg[16]; diff --git a/libs/JSystem/include/JSystem/JAudio2/JASCriticalSection.h b/libs/JSystem/include/JSystem/JAudio2/JASCriticalSection.h index 53faae80fe..ed4cb023ed 100644 --- a/libs/JSystem/include/JSystem/JAudio2/JASCriticalSection.h +++ b/libs/JSystem/include/JSystem/JAudio2/JASCriticalSection.h @@ -8,12 +8,18 @@ * */ class JASCriticalSection { +public: +#if TARGET_PC + JASCriticalSection(); + ~JASCriticalSection(); +#else public: JASCriticalSection() { mInterruptState = OSDisableInterrupts(); }; ~JASCriticalSection() { OSRestoreInterrupts(mInterruptState); }; private: u32 mInterruptState; +#endif }; #endif /* JASCRITICALSECTION_H */ diff --git a/libs/JSystem/include/JSystem/JAudio2/JASDSPChannel.h b/libs/JSystem/include/JSystem/JAudio2/JASDSPChannel.h index f843562f37..8204ab0838 100644 --- a/libs/JSystem/include/JSystem/JAudio2/JASDSPChannel.h +++ b/libs/JSystem/include/JSystem/JAudio2/JASDSPChannel.h @@ -5,9 +5,14 @@ /** * @ingroup jsystem-jaudio - * + * Responsible for allocating and prioritizing the available hardware DSP channels. */ struct JASDSPChannel { + /** + * Callback used to update DSP channel information on a regular basis. + * Parameters are a CallbackType, hardware channel, and specified user data. + * Return -1 to immediately abort playback. + */ typedef s32 (*Callback)(u32, JASDsp::TChannel*, void*); enum Status { @@ -17,9 +22,24 @@ struct JASDSPChannel { }; enum CallbackType { + /** + * Fired on a regular basis during play to update parameters. + */ /* 0 */ CB_PLAY, + + /** + * Fired once, when the channel starts playing. + */ /* 1 */ CB_START, + + /** + * Fired once, when the channel naturally finishes playing. + */ /* 2 */ CB_STOP, + + /** + * Fired once, if the channel is abruptly stopped due to an error or prioritization. + */ /* 3 */ CB_DROP, }; @@ -46,9 +66,13 @@ struct JASDSPChannel { static JASDSPChannel* sDspChannels; /* 0x00 */ s32 mStatus; + + /** + * Priority of this DSP channel. Used to + */ /* 0x04 */ s16 mPriority; /* 0x08 */ u32 mFlags; - /* 0x0C */ u32 field_0xc; + /* 0x0C */ u32 mUpdateCounter; /* 0x10 */ Callback mCallback; /* 0x14 */ void* mCallbackData; /* 0x18 */ JASDsp::TChannel* mChannel; diff --git a/libs/JSystem/include/JSystem/JAudio2/JASDSPInterface.h b/libs/JSystem/include/JSystem/JAudio2/JASDSPInterface.h index 44f2805bfe..a9a9b2d11e 100644 --- a/libs/JSystem/include/JSystem/JAudio2/JASDSPInterface.h +++ b/libs/JSystem/include/JSystem/JAudio2/JASDSPInterface.h @@ -4,6 +4,21 @@ #include #include +/** + * Amount of separate audio channels (i.e. individual playbacks, voices) the DSP can mix at once. + */ +#define DSP_CHANNELS 64 + +/** + * Amount of audio channels the DSP can calculate outputs for. + */ +#define DSP_OUTPUT_CHANNELS 6 // Presumed 5.1 surround + +/** + * Amount of audio samples rendered by the DSP in a single sub frame. + */ +#define DSP_SUBFRAME_SIZE 0x50 + struct JASWaveInfo; namespace JASDsp { @@ -30,6 +45,24 @@ namespace JASDsp { u16 field_0x10[8]; } FxBuf; + struct OutputChannelConfig { + u16 mBusConnect; + u16 mTargetVolume; + u16 mCurrentVolume; + + /** + * Gets upper 8 bits cleared when audio volume is changed mid-playback. + * Presumed to be some kind of progress used by the DSP to calculate position between + * mTargetVolume and mCurrentVolume. + */ + u16 mVolumeProgress; + }; + + /** + * DSP memory for each playback channel ("voice"). + * The DSP can read and write this memory. It is used as configuration, feedback, + * and working memory. + */ struct TChannel { void init(); void playStart(); @@ -37,67 +70,115 @@ namespace JASDsp { void replyFinishRequest(); void forceStop(); bool isActive() const; + + /** + * Check whether the DSP has finished playing this channel. + */ bool isFinish() const; void setWaveInfo(JASWaveInfo const&, u32, u32); void setOscInfo(u32); void initAutoMixer(); void setAutoMixer(u16, u8, u8, u8, u8); void setPitch(u16); - void setMixerInitVolume(u8, s16); - void setMixerVolume(u8, s16); + void setMixerInitVolume(u8 outputChannel, s16 volume); + void setMixerVolume(u8 outputChannel, s16 volume); void setPauseFlag(u8); + + /** + * Flushes backing memory of channel out of the data cache. + */ void flush(); void initFilter(); void setFilterMode(u16); void setIIRFilterParam(s16*); void setFIR8FilterParam(s16*); void setDistFilter(s16); - void setBusConnect(u8, u8); + void setBusConnect(u8 outputChannel, u8 param_1); + /** + * Whether this channel is currently actively playing audio. + */ /* 0x000 */ u16 mIsActive; + + /** + * Written by DSP to indicate playback has finished. + */ /* 0x002 */ u16 mIsFinished; + + /** + * Pitch shift via changing playback speed. + */ /* 0x004 */ u16 mPitch; - /* 0x006 */ short field_0x006; - /* 0x008 */ u16 field_0x008; - /* 0x00A */ u8 field_0x00A[0x00C - 0x00A]; + /* 0x006 */ short _unused1; + + /** + * Set to 1 when playback starts, cleared by DSP later, + * checked by JASAramStream before actually doing processing. + * Presumably to instruct DSP to clear state? + * (Corroborated by fields JASAramStream checks never being cleared explicitly by CPU.) + */ + /* 0x008 */ u16 mResetFlag; + /* 0x00A */ u8 _unused2[0x00C - 0x00A]; /* 0x00C */ s16 mPauseFlag; - /* 0x00E */ short field_0x00E; - /* 0x010 */ u16 field_0x010[1][4]; // array size unknown - /* 0x018 */ u8 field_0x018[0x050 - 0x018]; - /* 0x050 */ u16 field_0x050; - /* 0x052 */ u16 field_0x052; - /* 0x054 */ u16 field_0x054; - /* 0x056 */ u16 field_0x056; - /* 0x058 */ u16 field_0x058; - /* 0x05A */ u8 field_0x05A[0x060 - 0x05A]; - /* 0x060 */ short field_0x060; - /* 0x062 */ u8 field_0x062[0x064 - 0x062]; - /* 0x064 */ u16 field_0x064; - /* 0x066 */ short field_0x066; - /* 0x068 */ int field_0x068; - /* 0x06C */ u8 field_0x06C[0x070 - 0x06C]; - /* 0x070 */ int field_0x070; - /* 0x074 */ int field_0x074; - /* 0x078 */ short field_0x078[4]; - /* 0x080 */ short field_0x080[20]; - /* 0x0A8 */ short field_0x0a8[4]; - /* 0x0B0 */ u16 field_0x0b0[16]; - /* 0x0D0 */ u8 field_0x0D0[0x100 - 0x0D0]; - /* 0x100 */ u16 field_0x100; - /* 0x102 */ u16 field_0x102; - /* 0x104 */ s16 field_0x104; - /* 0x106 */ s16 field_0x106; + /* 0x00E */ short _unused3; + /* 0x010 */ OutputChannelConfig mOutputChannels[DSP_OUTPUT_CHANNELS]; + /* 0x040 */ u8 _unused4[0x050 - 0x040]; + /* 0x050 */ u16 mAutoMixerPanDolby; // pan is upper 8 bits, dolby lower 8. + /* 0x052 */ u16 mAutoMixerFxMix; + /* 0x054 */ u16 mAutoMixerInitVolume; + /* 0x056 */ u16 mAutoMixerVolume; + /* 0x058 */ u16 mAutoMixerBeenSet; + /* 0x05A */ u8 _unused5[0x060 - 0x05A]; + /* 0x060 */ short field_0x060; // Only cleared to zero, presumed used by DSP. + /* 0x062 */ u8 _unused6[0x064 - 0x062]; + + /** + * Samples per ADPCM frame for ADPCM audio. Seems just set to 1 for PCM formats. + * Name could use improvement, probably? + */ + /* 0x064 */ u16 mSamplesPerBlock; + /* 0x066 */ short field_0x066; // Only cleared to zero, presumed used by DSP. + /* 0x068 */ u32 mSamplePosition; // Only ever initialized by code, name is guess. + /* 0x06C */ u8 _unused7[0x070 - 0x06C]; + + /** + * Current audio read position in ARAM. Updated by DSP. + */ + /* 0x070 */ u32 mAramStreamPosition; + + /** + * Amount of (decoded) audio samples left until the end of the buffer. + * Gets written by DSP, but also CPU. + */ + /* 0x074 */ u32 mSamplesLeft; // Never directly cleared to zero. Seems sus. Cleared by DSP? + /* 0x078 */ short field_0x078[4]; // Only cleared to zero, presumed used by DSP. + /* 0x080 */ short field_0x080[20]; // Only cleared to zero, presumed used by DSP. + /* 0x0A8 */ short field_0x0a8[4]; // Only cleared to zero, presumed used by DSP. + /* 0x0B0 */ u16 field_0x0b0[16]; // Only cleared to zero, presumed used by DSP. + /* 0x0D0 */ u8 _unused8[0x100 - 0x0D0]; + /* 0x100 */ u16 mBytesPerBlock; + /* 0x102 */ u16 mLoopFlag; + + /** + * Used for decoding ADPCM data around loop edges. + */ + /* 0x104 */ s16 mpLast; + + /** + * Used for decoding ADPCM data around loop edges. + */ + /* 0x106 */ s16 mpPenult; /* 0x108 */ u16 mFilterMode; /* 0x10A */ u16 mForcedStop; /* 0x10C */ int field_0x10c; - /* 0x110 */ u32 field_0x110; - /* 0x114 */ u32 field_0x114; - /* 0x118 */ u32 field_0x118; - /* 0x11C */ int field_0x11c; + /* 0x110 */ u32 mLoopStartSample; + /* 0x114 */ u32 mEndSample; + /* 0x118 */ u32 mWaveAramAddress; + /* 0x11C */ int mSampleCount; /* 0x120 */ s16 fir_filter_params[8]; - /* 0x130 */ u8 field_0x130[0x148 - 0x130]; + /* 0x130 */ u8 _unused9[0x148 - 0x130]; /* 0x148 */ s16 iir_filter_params[8]; - /* 0x158 */ u8 field_0x158[0x180 - 0x158]; + /* 0x158 */ u8 _unused10[0x180 - 0x158]; }; void boot(void (*)(void*)); diff --git a/libs/JSystem/include/JSystem/JAudio2/JASDriverIF.h b/libs/JSystem/include/JSystem/JAudio2/JASDriverIF.h index 319c826345..5cddc38596 100644 --- a/libs/JSystem/include/JSystem/JAudio2/JASDriverIF.h +++ b/libs/JSystem/include/JSystem/JAudio2/JASDriverIF.h @@ -3,6 +3,10 @@ #include "JSystem/JAudio2/JASCallback.h" +#define JAS_OUTPUT_MONO OS_SOUND_MODE_MONO +#define JAS_OUTPUT_STEREO OS_SOUND_MODE_STEREO +#define JAS_OUTPUT_SURROUND 2 + typedef s32 (*DriverCallback)(void*); namespace JASDriver { diff --git a/libs/JSystem/include/JSystem/JAudio2/JASHeapCtrl.h b/libs/JSystem/include/JSystem/JAudio2/JASHeapCtrl.h index 70f63bc889..8e1381cda3 100644 --- a/libs/JSystem/include/JSystem/JAudio2/JASHeapCtrl.h +++ b/libs/JSystem/include/JSystem/JAudio2/JASHeapCtrl.h @@ -352,6 +352,28 @@ template JASMemPool JASPoolAllocObject::memPool_; template class JASMemPool_MultiThreaded : public JASGenericMemPool { public: +#if TARGET_PC + OSMutex mutex; + + JASMemPool_MultiThreaded() { + OSInitMutex(&mutex); + } + + void newMemPool(int param_0) { + JASThreadingModel::ObjectLevelLockable::Lock lock(mutex); + JASGenericMemPool::newMemPool(sizeof(T), param_0); + } + + void* alloc(size_t count) { + JASThreadingModel::ObjectLevelLockable::Lock lock(mutex); + return JASGenericMemPool::alloc(count); + } + + void free(void* ptr, u32 param_1) { + JASThreadingModel::ObjectLevelLockable::Lock lock(mutex); + JASGenericMemPool::free(ptr, param_1); + } +#else void newMemPool(int param_0) { typename JASThreadingModel::InterruptsDisable >::Lock lock(*this); JASGenericMemPool::newMemPool(sizeof(T), param_0); @@ -366,6 +388,7 @@ public: typename JASThreadingModel::InterruptsDisable >::Lock lock(*this); JASGenericMemPool::free(ptr, param_1); } +#endif }; /** diff --git a/libs/JSystem/include/JSystem/JAudio2/JASOscillator.h b/libs/JSystem/include/JSystem/JAudio2/JASOscillator.h index 746d462e12..e811e890ab 100644 --- a/libs/JSystem/include/JSystem/JAudio2/JASOscillator.h +++ b/libs/JSystem/include/JSystem/JAudio2/JASOscillator.h @@ -9,10 +9,21 @@ * */ struct JASOscillator { + enum EnvelopeMode { + /* 0x0 */ ENVELOPE_LINEAR, + /* 0x1 */ ENVELOPE_SQUARE, + /* 0x2 */ ENVELOPE_SQUARE_ROOT, + /* 0x3 */ ENVELOPE_SAMPLE_CELL, + + ENVELOPE_LOOP = 0xD, + ENVELOPE_HOLD = 0xE, + ENVELOPE_STOP = 0xF, + }; + struct Point { - /* 0x0 */ BE(s16) _0; - /* 0x2 */ BE(s16) _2; - /* 0x4 */ BE(s16) _4; + /* 0x0 */ BE(s16) mEnvelopeMode; // EnvelopeMode + /* 0x2 */ BE(s16) mTime; + /* 0x4 */ BE(s16) mValue; }; struct EffectParams { @@ -37,11 +48,11 @@ struct JASOscillator { struct Data { /* 0x00 */ u32 mTarget; - /* 0x04 */ f32 _04; + /* 0x04 */ f32 mRate; /* 0x08 */ const Point* mTable; /* 0x0C */ const Point* rel_table; - /* 0x10 */ f32 mScale; - /* 0x14 */ f32 _14; + /* 0x10 */ f32 mScale; // aka width + /* 0x14 */ f32 mVertex; }; enum Target { @@ -75,9 +86,9 @@ struct JASOscillator { /* 0x08 */ f32 _08; /* 0x0C */ f32 _0C; /* 0x10 */ f32 _10; - /* 0x14 */ u16 _14; + /* 0x14 */ u16 mCurPoint; /* 0x16 */ u16 mDirectRelease; - /* 0x18 */ u8 _18; + /* 0x18 */ u8 mEnvelopeMode; // EnvelopeMode /* 0x1A */ u16 _1A; /* 0x1C */ int _1C; diff --git a/libs/JSystem/include/JSystem/JAudio2/JASSeqParser.h b/libs/JSystem/include/JSystem/JAudio2/JASSeqParser.h index 096cbadd98..51db04ba26 100644 --- a/libs/JSystem/include/JSystem/JAudio2/JASSeqParser.h +++ b/libs/JSystem/include/JSystem/JAudio2/JASSeqParser.h @@ -14,9 +14,9 @@ public: enum BranchCondition {}; struct CmdInfo { - s32 (JASSeqParser::*field_0x0)(JASTrack*, u32*); - u16 field_0xc; - u16 field_0xe; + s32 (JASSeqParser::*mHandler)(JASTrack*, u32*); + u16 mParameterCount; + u16 mParameterTypes; }; virtual ~JASSeqParser() {} diff --git a/libs/JSystem/include/JSystem/JAudio2/JASSeqReader.h b/libs/JSystem/include/JSystem/JAudio2/JASSeqReader.h index 9dce7f56f7..878713602a 100644 --- a/libs/JSystem/include/JSystem/JAudio2/JASSeqReader.h +++ b/libs/JSystem/include/JSystem/JAudio2/JASSeqReader.h @@ -3,6 +3,8 @@ #include +#define JAS_SEQ_STACK_SIZE 8 + /** * @ingroup jsystem-jaudio * @@ -19,55 +21,55 @@ public: int readMidiValue(); void jump(u32 param_1) { - field_0x04 = field_0x00 + param_1; + mCurPos = mBase + param_1; } void jump(void* param_1) { - field_0x04 = (u8*)param_1; + mCurPos = (u8*)param_1; } u32 get24(u32 param_0) const { - return (*(u32*)(field_0x00 + param_0 - 1)) & 0xffffff; + return (*(BE(u32)*)(mBase + param_0 - 1)) & 0xffffff; } - u32* getBase() { return (u32*)field_0x00; } - void* getAddr(u32 param_0) { return field_0x00 + param_0; } - u8 getByte(u32 param_0) const { return *(field_0x00 + param_0); } - u16 get16(u32 param_0) const { return *(u16*)(field_0x00 + param_0); } - u32 get32(u32 param_0) const { return *(u32*)(field_0x00 + param_0); } - u8* getCur() { return field_0x04; } - u32 readByte() { return *field_0x04++; } + u32* getBase() { return (u32*)mBase; } + void* getAddr(u32 param_0) { return mBase + param_0; } + u8 getByte(u32 param_0) const { return *(mBase + param_0); } + u16 get16(u32 param_0) const { return *(BE(u16)*)(mBase + param_0); } + u32 get32(u32 param_0) const { return *(BE(u32)*)(mBase + param_0); } + u8* getCur() { return mCurPos; } + u32 readByte() { return *mCurPos++; } u32 read16() { #ifdef __MWERKS__ - return *((u16*)field_0x04)++; + return *((u16*)mCurPos)++; #else - u16* value = (u16*)field_0x04; - field_0x04 += 2; + BE(u16)* value = (BE(u16)*)mCurPos; + mCurPos += 2; return *value; #endif } u32 read24() { - field_0x04--; + mCurPos--; #ifdef __MWERKS__ - return (*((u32*)field_0x04)++) & 0x00ffffff; + return (*((u32*)mCurPos)++) & 0x00ffffff; #else - u32* value = (u32*)field_0x04; - field_0x04 += 4; + BE(u32)* value = (BE(u32)*)mCurPos; + mCurPos += 4; return (*value) & 0x00ffffff; #endif } u16 getLoopCount() const { - if (field_0x08 == 0) { + if (mCurStackDepth == 0) { return 0; } - return field_0x2c[field_0x08 - 1]; + return mLoopCount[mCurStackDepth - 1]; } - /* 0x00 */ u8* field_0x00; - /* 0x04 */ u8* field_0x04; - /* 0x08 */ u32 field_0x08; - /* 0x0C */ u16* field_0x0c[8]; - /* 0x2C */ u16 field_0x2c[8]; + /* 0x00 */ u8* mBase; + /* 0x04 */ u8* mCurPos; + /* 0x08 */ u32 mCurStackDepth; + /* 0x0C */ u16* mReturnAddr[JAS_SEQ_STACK_SIZE]; + /* 0x2C */ u16 mLoopCount[JAS_SEQ_STACK_SIZE]; }; #endif /* JASSEQREADER_H */ diff --git a/libs/JSystem/include/JSystem/JAudio2/JASTrack.h b/libs/JSystem/include/JSystem/JAudio2/JASTrack.h index 796bb6afd7..b54a98aa77 100644 --- a/libs/JSystem/include/JSystem/JAudio2/JASTrack.h +++ b/libs/JSystem/include/JSystem/JAudio2/JASTrack.h @@ -54,7 +54,7 @@ struct JASTrack : public JASPoolAllocObject_MultiThreaded { /* 0x4c */ JASTrack* mTrack; }; - struct TList : JGadget::TLinkList { + struct TList : JGadget::TLinkList { TList() : mCallbackRegistered(false) {} void append(JASTrack*); void seqMain(); diff --git a/libs/JSystem/include/JSystem/JAudio2/JASTrackPort.h b/libs/JSystem/include/JSystem/JAudio2/JASTrackPort.h index 393a701c27..781da78049 100644 --- a/libs/JSystem/include/JSystem/JAudio2/JASTrackPort.h +++ b/libs/JSystem/include/JSystem/JAudio2/JASTrackPort.h @@ -19,12 +19,12 @@ public: u32 checkImport(u32) const; u32 checkExport(u32) const; - u16 get(u32 param_0) const { return field_0x4[param_0]; } - void set(u32 param_0, u16 param_1) { field_0x4[param_0] = param_1; } + u16 get(u32 param_0) const { return mPortValues[param_0]; } + void set(u32 param_0, u16 param_1) { mPortValues[param_0] = param_1; } u16 field_0x0; u16 field_0x2; - u16 field_0x4[MAX_PORTS]; + u16 mPortValues[MAX_PORTS]; }; #endif /* JASTRACKPORT_H */ diff --git a/libs/JSystem/include/JSystem/JAudio2/JASWSParser.h b/libs/JSystem/include/JSystem/JAudio2/JASWSParser.h index 020158c096..68d91006ba 100644 --- a/libs/JSystem/include/JSystem/JAudio2/JASWSParser.h +++ b/libs/JSystem/include/JSystem/JAudio2/JASWSParser.h @@ -31,26 +31,28 @@ public: struct TWave { /* 0x00 */ u8 _00; - /* 0x01 */ u8 _01; - /* 0x02 */ u8 _02; - /* 0x04 */ BE(f32) _04; - /* 0x08 */ BE(u32) mOffset; - /* 0x0C */ BE(u32) _0C; - /* 0x10 */ BE(u32) _10; - /* 0x14 */ BE(u32) _14; - /* 0x18 */ BE(u32) _18; - /* 0x1C */ BE(u32) _1C; - /* 0x20 */ BE(s16) _20; - /* 0x22 */ BE(s16) _22; + /* 0x01 */ u8 mWaveFormat; + /* 0x02 */ u8 mBaseKey; + /* 0x04 */ BE(f32) mSampleRate; + /* 0x08 */ BE(u32) mAWOffsetStart; + /* 0x0C */ BE(u32) mAWOffsetEnd; + /* 0x10 */ BE(u32) mLoopFlags; + /* 0x14 */ BE(u32) mLoopStartSample; + /* 0x18 */ BE(u32) mLoopEndSample; + /* 0x1C */ BE(u32) mSampleCount; + /* 0x20 */ BE(s16) mpLast; + /* 0x22 */ BE(s16) mpPenult; }; struct TWaveArchive { - /* 0x00 */ char mFileName[0x74]; // unknown length + /* 0x00 */ char mFileName[0x70]; + /* 0x70 */ BE(u32) mWaveCount; /* 0x74 */ TOffset mWaveOffsets[0]; }; struct TWaveArchiveBank { - /* 0x0 */ u8 _00[8]; + /* 0x0 */ BE(u32) mMagic; // 'WINF' + /* 0x0 */ BE(u32) mArchiveCounts; /* 0x8 */ TOffset mArchiveOffsets[0]; }; @@ -66,14 +68,17 @@ public: }; struct TCtrlGroup { - /* 0x0 */ u8 _00[8]; + /* 0x0 */ BE(u32) mMagic; // 'WBCT' + /* 0x4 */ u32 mUnknown; /* 0x8 */ BE(u32) mGroupCount; /* 0xC */ TOffset mCtrlSceneOffsets[0]; }; /** @fabricated */ struct THeader { - /* 0x00 */ u8 _00[0xC]; + /* 0x00 */ BE(u32) mMagic; // 'WSYS' + /* 0x04 */ BE(u32) mSize; + /* 0x08 */ BE(u32) mId; /* 0x0C */ BE(u32) mWaveTableSize; /* 0x10 */ TOffset mArchiveBankOffset; /* 0x14 */ TOffset mCtrlGroupOffset; diff --git a/libs/JSystem/include/JSystem/JAudio2/JASWaveInfo.h b/libs/JSystem/include/JSystem/JAudio2/JASWaveInfo.h index cbff6d3ac2..cac518836e 100644 --- a/libs/JSystem/include/JSystem/JAudio2/JASWaveInfo.h +++ b/libs/JSystem/include/JSystem/JAudio2/JASWaveInfo.h @@ -3,7 +3,12 @@ #include -class JASWaveArc; +struct JASWaveArc; + +#define WAVE_FORMAT_ADPCM4 0 +#define WAVE_FORMAT_ADPCM2 1 +#define WAVE_FORMAT_PCM8 2 +#define WAVE_FORMAT_PCM16 3 /** * @ingroup jsystem-jaudio @@ -11,21 +16,21 @@ class JASWaveArc; */ struct JASWaveInfo { JASWaveInfo() { - field_0x01 = 0x3c; + mBaseKey = 0x3c; field_0x20 = &one; } - /* 0x00 */ u8 field_0x00; - /* 0x01 */ u8 field_0x01; - /* 0x02 */ u8 field_0x02; - /* 0x04 */ f32 field_0x04; - /* 0x08 */ int field_0x08; - /* 0x0C */ int field_0x0c; - /* 0x10 */ u32 field_0x10; - /* 0x14 */ int field_0x14; - /* 0x18 */ int field_0x18; - /* 0x1C */ s16 field_0x1c; - /* 0x1E */ s16 field_0x1e; + /* 0x00 */ u8 mWaveFormat; + /* 0x01 */ u8 mBaseKey; + /* 0x02 */ u8 mLoopFlag; + /* 0x04 */ f32 mSampleRate; + /* 0x08 */ int mOffsetStart; + /* 0x0C */ int mOffsetLength; + /* 0x10 */ u32 mLoopStartSample; + /* 0x14 */ int mLoopEndSample; + /* 0x18 */ int mSampleCount; + /* 0x1C */ s16 mpLast; + /* 0x1E */ s16 mpPenult; /* 0x20 */ const u32* field_0x20; static u32 one; diff --git a/libs/JSystem/include/JSystem/JAudio2/JAUAudibleParam.h b/libs/JSystem/include/JSystem/JAudio2/JAUAudibleParam.h index 89b016cb0a..50f5b45f09 100644 --- a/libs/JSystem/include/JSystem/JAudio2/JAUAudibleParam.h +++ b/libs/JSystem/include/JSystem/JAudio2/JAUAudibleParam.h @@ -2,6 +2,7 @@ #define JAUAUDIBLEPARAM_H #include +#include "dusk/endian.h" /** * @ingroup jsystem-jaudio @@ -14,8 +15,8 @@ struct JAUAudibleParam { union { struct { - u16 f0; - u16 f1; + BE(u16) f0; + BE(u16) f1; } half; struct { u8 b0_0 : 4; @@ -29,7 +30,7 @@ struct JAUAudibleParam { u8 b2; u8 b3; } bytes; - u32 raw; + BE(u32) raw; } field_0x0; }; diff --git a/libs/JSystem/include/JSystem/JAudio2/JAUInitializer.h b/libs/JSystem/include/JSystem/JAudio2/JAUInitializer.h index 8b5090c580..9f9e5bc6fd 100644 --- a/libs/JSystem/include/JSystem/JAudio2/JAUInitializer.h +++ b/libs/JSystem/include/JSystem/JAudio2/JAUInitializer.h @@ -21,7 +21,7 @@ public: /* 0x10 */ int audioThreadPriority_; /* 0x14 */ int dvdThreadId_; /* 0x18 */ int audioThreadId_; - /* 0x1C */ int field_0x1c; + /* 0x1C */ int mJasTrackPoolSize; /* 0x20 */ int field_0x20; /* 0x24 */ int aramBlockSize_; /* 0x28 */ int aramChannelNum_; @@ -38,10 +38,10 @@ public: JAU_JAIInitializer(); void initJAInterface(); - int field_0x0; - int field_0x4; - int field_0x8; - int field_0xc; + int mJaiSePoolSize; + int mJaiSeqPoolSize; + int mJaiStreamPoolSize; + int mJaiSoundChildPoolSize; }; #endif /* JAUINITIALIZER_H */ diff --git a/libs/JSystem/include/JSystem/JAudio2/JAUSeqCollection.h b/libs/JSystem/include/JSystem/JAudio2/JAUSeqCollection.h index 1812976e2f..bfc88ef3ad 100644 --- a/libs/JSystem/include/JSystem/JAudio2/JAUSeqCollection.h +++ b/libs/JSystem/include/JSystem/JAudio2/JAUSeqCollection.h @@ -11,11 +11,11 @@ struct JAISeqDataRegion; * */ struct JAUSeqCollectionData { - s8 field_0x0; - s8 field_0x1; - BE(u16) field_0x2; - BE(u32) field_0x4; - BE(u32) field_0x8; + s8 mMagic1; // 'S' + s8 mMagic2; // 'C' + BE(u16) mNumSoundCategories; + BE(u32) mSectionSize; + BE(u32) mTableOffsets[0]; // VLA }; /** @@ -29,12 +29,12 @@ public: bool getSeqData(int, int, JAISeqData*); bool getSeqDataRegion(JAISeqDataRegion*); - bool isValid() const { return field_0x8; } + bool isValid() const { return mHeader; } - /* 0x00 */ u16 field_0x0; - /* 0x04 */ const BE(u32)* field_0x4; - /* 0x08 */ const JAUSeqCollectionData* field_0x8; - /* 0x0C */ int field_0xc; + /* 0x00 */ u16 mNumSoundCategories; + /* 0x04 */ const BE(u32)* mTableOffsets; + /* 0x08 */ const JAUSeqCollectionData* mHeader; + /* 0x0C */ u32 mSectionSize; }; /** @@ -49,7 +49,7 @@ public: SeqDataReturnValue getSeqData(JAISoundID, JAISeqData*); ~JAUSeqDataMgr_SeqCollection(); - const void* getResource() const { return field_0x4; } + const void* getResource() const { return mTableOffsets; } void init(const void* param_1) { JAUSeqCollection::init(param_1); } /* 0x14 */ JAISeqDataUser* user_; diff --git a/libs/JSystem/include/JSystem/JAudio2/JAUSoundAnimator.h b/libs/JSystem/include/JSystem/JAudio2/JAUSoundAnimator.h index b9e1d433c9..e81cd70ee4 100644 --- a/libs/JSystem/include/JSystem/JAudio2/JAUSoundAnimator.h +++ b/libs/JSystem/include/JSystem/JAudio2/JAUSoundAnimator.h @@ -2,6 +2,7 @@ #define JAUSOUNDANIMATOR_H #include "JSystem/JAudio2/JAISound.h" +#include "dusk/offset_ptr.h" class JAUSoundAnimation; @@ -62,10 +63,10 @@ public: } /* 0x00 */ JAISoundID mSoundId; - /* 0x04 */ f32 field_0x04; - /* 0x08 */ f32 field_0x08; - /* 0x0C */ f32 field_0x0c; - /* 0x10 */ u32 mFlags; + /* 0x04 */ BE(f32) field_0x04; + /* 0x08 */ BE(f32) field_0x08; + /* 0x0C */ BE(f32) field_0x0c; + /* 0x10 */ BE(u32) mFlags; /* 0x14 */ u8 field_0x14; /* 0x15 */ u8 field_0x15; /* 0x16 */ u8 field_0x16; @@ -97,23 +98,31 @@ public: int getEndSoundIndex(f32) const; u16 getNumSounds() const { +#if TARGET_PC + return mNumSounds; +#else if (mControl != NULL) { return mControl->getNumSounds(this); } else { return mNumSounds; } +#endif } const JAUSoundAnimationSound* getSound(int i_index) const { +#if TARGET_PC + return &mSounds + i_index; +#else if (mControl != NULL) { return mControl->getSound(this, i_index); } else { return &mSounds + i_index; } +#endif } - /* 0x0 */ u16 mNumSounds; - /* 0x4 */ JAUSoundAnimationControl* mControl; + /* 0x0 */ BE(u16) mNumSounds; + /* 0x4 */ OFFSET_PTR(JAUSoundAnimationControl) mControl; /* 0x8 */ JAUSoundAnimationSound mSounds; // actually an array }; diff --git a/libs/JSystem/include/JSystem/JAudio2/JAUSoundTable.h b/libs/JSystem/include/JSystem/JAudio2/JAUSoundTable.h index b7eaee0ffe..5dab15abc0 100644 --- a/libs/JSystem/include/JSystem/JAudio2/JAUSoundTable.h +++ b/libs/JSystem/include/JSystem/JAudio2/JAUSoundTable.h @@ -12,9 +12,9 @@ struct JAUSoundTableItem { u8 mPriority; u8 field_0x1; - u16 mResourceId; - u32 field_0x4; - f32 field_0x8; + BE(u16) mResourceId; + BE(u32) field_0x4; + BE(f32) field_0x8; }; /** diff --git a/libs/JSystem/include/JSystem/JAudio2/JAUStreamAramMgr.h b/libs/JSystem/include/JSystem/JAudio2/JAUStreamAramMgr.h index bf861b495d..f1cfe8f7f6 100644 --- a/libs/JSystem/include/JSystem/JAudio2/JAUStreamAramMgr.h +++ b/libs/JSystem/include/JSystem/JAudio2/JAUStreamAramMgr.h @@ -48,13 +48,13 @@ template class JAUStreamStaticAramMgr_ : public JAUStreamAramMgrBase_ { public: JAUStreamStaticAramMgr_() { field_0x4c = 0; } - virtual void* newStreamAram(u32* param_0) { + virtual void* newStreamAram(u32* size) { for (u32 i = 0; i < field_0x4c; i++) { if (this->field_0x4.test(i)) { continue; } this->field_0x4.set(i, true); - *param_0 = this->mHeaps[i].getSize(); + *size = this->mHeaps[i].getSize(); return this->mHeaps[i].getBase(); } return NULL; diff --git a/libs/JSystem/include/JSystem/JAudio2/dspproc.h b/libs/JSystem/include/JSystem/JAudio2/dspproc.h index 868080031a..c49c143fe4 100644 --- a/libs/JSystem/include/JSystem/JAudio2/dspproc.h +++ b/libs/JSystem/include/JSystem/JAudio2/dspproc.h @@ -4,7 +4,7 @@ #include void DSPReleaseHalt2(u32 msg); -void DsetupTable(u32 param_0, u32 param_1, u32 param_2, u32 param_3, u32 param_4); +void DsetupTable(u32 channelCount, u32 channelBufferAddress, u32 param_2, u32 param_3, u32 param_4); void DsetMixerLevel(f32 level); void DsyncFrame2ch(u32 param_0, u32 param_1, u32 param_2); void DsyncFrame4ch(u32 param_0, u32 param_1, u32 param_2, u32 param_3, u32 param_4); diff --git a/libs/JSystem/include/JSystem/JAudio2/dsptask.h b/libs/JSystem/include/JSystem/JAudio2/dsptask.h index 8042d1884b..7dbcff2dec 100644 --- a/libs/JSystem/include/JSystem/JAudio2/dsptask.h +++ b/libs/JSystem/include/JSystem/JAudio2/dsptask.h @@ -3,7 +3,7 @@ #include -void DspBoot(void (*)(void*)); +void DspBoot(void (*requestCallback)(void*)); void DspFinishWork(u16 param_0); int DSPSendCommands2(u32* msgs, u32 param_1, void (*param_2)(u16)); diff --git a/libs/JSystem/include/JSystem/JKernel/JKRHeap.h b/libs/JSystem/include/JSystem/JKernel/JKRHeap.h index d988f09d74..d3710bd5df 100644 --- a/libs/JSystem/include/JSystem/JKernel/JKRHeap.h +++ b/libs/JSystem/include/JSystem/JKernel/JKRHeap.h @@ -283,7 +283,18 @@ void jkrDelete(T* ptr) { return; } ptr->~T(); - operator delete(ptr, JKRHeapToken::Dummy); + + if constexpr (requires { T::operator delete(ptr, JKRHeapToken::Dummy); }) { + T::operator delete(ptr, JKRHeapToken::Dummy); + } else if constexpr (requires { T::operator delete(ptr, sizeof(T), JKRHeapToken::Dummy); }) { + T::operator delete(ptr, sizeof(T), JKRHeapToken::Dummy); + } else if constexpr (requires { T::operator delete(ptr); }) { + T::operator delete(ptr); + } else if constexpr (requires { T::operator delete(ptr, sizeof(T)); }) { + T::operator delete(ptr, sizeof(T)); + } else { + operator delete(ptr, JKRHeapToken::Dummy); + } } template<> diff --git a/libs/JSystem/include/JSystem/JKernel/JKRThread.h b/libs/JSystem/include/JSystem/JKernel/JKRThread.h index b58dc6232d..2830252281 100644 --- a/libs/JSystem/include/JSystem/JKernel/JKRThread.h +++ b/libs/JSystem/include/JSystem/JKernel/JKRThread.h @@ -132,6 +132,10 @@ public: static JSUList sThreadList; // static u8 sThreadList[12]; + +#if TARGET_PC + const char* mThreadName; +#endif }; class JKRIdleThread : public JKRThread { diff --git a/libs/JSystem/src/J3DGraphBase/J3DSys.cpp b/libs/JSystem/src/J3DGraphBase/J3DSys.cpp index c34ba546f0..2f9cf51a89 100644 --- a/libs/JSystem/src/J3DGraphBase/J3DSys.cpp +++ b/libs/JSystem/src/J3DGraphBase/J3DSys.cpp @@ -17,7 +17,11 @@ Vec J3DSys::mParentS; J3DTexCoordScaleInfo J3DSys::sTexCoordScaleTable[8]; +#if TARGET_PC // Original game bug, array is too small. +static u8 NullTexData[0x20] ATTRIBUTE_ALIGN(32) = {0}; +#else static u8 NullTexData[0x10] ATTRIBUTE_ALIGN(32) = {0}; +#endif static Mtx j3dIdentityMtx = { 1.0f, 0.0f, 0.0f, 0.0f, diff --git a/libs/JSystem/src/JAudio2/JAIAudience.cpp b/libs/JSystem/src/JAudio2/JAIAudience.cpp index 3e1205e2fc..a14422a943 100644 --- a/libs/JSystem/src/JAudio2/JAIAudience.cpp +++ b/libs/JSystem/src/JAudio2/JAIAudience.cpp @@ -1,11 +1,20 @@ #include "JSystem/JSystem.h" // IWYU pragma: keep #include "JSystem/JAudio2/JAIAudience.h" + #include "JSystem/JAudio2/JAISeMgr.h" #include "JSystem/JAudio2/JAISeqMgr.h" #include "JSystem/JAudio2/JAIStreamMgr.h" +#include "dusk/main.h" JAIAudience::~JAIAudience() { +#if TARGET_PC + if (dusk::IsShuttingDown) { + // Those asserts down there crash on shutdown from dtors. + return; + } +#endif + JUT_ASSERT(14, ! JAISeMgr::getInstance() || ( JAISeMgr::getInstance() ->getAudience() != this )); JUT_ASSERT(15, ! JAISeqMgr::getInstance() || ( JAISeqMgr::getInstance() ->getAudience() != this )); JUT_ASSERT(16, ! JAIStreamMgr::getInstance() || ( JAIStreamMgr::getInstance() ->getAudience() != this )); diff --git a/libs/JSystem/src/JAudio2/JAISe.cpp b/libs/JSystem/src/JAudio2/JAISe.cpp index 4e453811a9..504c875bad 100644 --- a/libs/JSystem/src/JAudio2/JAISe.cpp +++ b/libs/JSystem/src/JAudio2/JAISe.cpp @@ -57,7 +57,7 @@ void JAISe::startTrack_(const JASSoundParams& params) { } inner_.field_0x26c = 1; - inner_.track.setSeqData(inner_.mSeqData.field_0x0, inner_.mSeqData.field_0x4); + inner_.track.setSeqData(inner_.mSeqData.mBase, inner_.mSeqData.mOffset); inner_.track.startSeq(); } diff --git a/libs/JSystem/src/JAudio2/JAISeq.cpp b/libs/JSystem/src/JAudio2/JAISeq.cpp index e3d07d5418..c05494b82e 100644 --- a/libs/JSystem/src/JAudio2/JAISeq.cpp +++ b/libs/JSystem/src/JAudio2/JAISeq.cpp @@ -40,7 +40,7 @@ void JAISeq::JAISeqMgr_startID_(JAISoundID id, const JGeometry::TVec3* posP void JAISeq::playSeqData_(const JASSoundParams& params, JAISoundActivity activity) { JUT_ASSERT(72, JASTrack_isFreeOrStopped( & inner_.outputTrack )); - inner_.outputTrack.setSeqData(inner_.mSeqData.field_0x0, inner_.mSeqData.field_0x4); + inner_.outputTrack.setSeqData(inner_.mSeqData.mBase, inner_.mSeqData.mOffset); if (audible_) { initTrack_JAISound_(&inner_.outputTrack); } else { diff --git a/libs/JSystem/src/JAudio2/JAIStream.cpp b/libs/JSystem/src/JAudio2/JAIStream.cpp index 72f37ec248..5799080b12 100644 --- a/libs/JSystem/src/JAudio2/JAIStream.cpp +++ b/libs/JSystem/src/JAudio2/JAIStream.cpp @@ -48,7 +48,7 @@ void JAIStream::JAIStreamMgr_startID_(JAISoundID id, s32 streamFileEntry, } bool JAIStream::prepare_prepareStream_() { - u32 local_28; + u32 size; JAIStreamAramMgr* streamAramMgr; switch (field_0x290) { @@ -56,9 +56,9 @@ bool JAIStream::prepare_prepareStream_() { streamAramMgr = streamMgr_->getStreamAramMgr(); JUT_ASSERT(100, streamAramMgr); - streamAramAddr_ = streamAramMgr->newStreamAram(&local_28); + streamAramAddr_ = streamAramMgr->newStreamAram(&size); if (streamAramAddr_ != NULL) { - inner_.aramStream_.init((uintptr_t)streamAramAddr_, local_28, &JAIStream_JASAramStreamCallback_, this); + inner_.aramStream_.init((uintptr_t)streamAramAddr_, size, &JAIStream_JASAramStreamCallback_, this); field_0x290 = 1; prepareCount_ = 0; } else { diff --git a/libs/JSystem/src/JAudio2/JASAiCtrl.cpp b/libs/JSystem/src/JAudio2/JASAiCtrl.cpp index 4e1c296388..1285d68359 100644 --- a/libs/JSystem/src/JAudio2/JASAiCtrl.cpp +++ b/libs/JSystem/src/JAudio2/JASAiCtrl.cpp @@ -98,7 +98,10 @@ void JASDriver::setOutputRate(JASOutputRate param_0) { sSubFrames = 10; sDacRate = 48000.0f; } + +#if !TARGET_PC sDacRate *= 1.0008897f; +#endif } const JASDriver::MixFunc JASDriver::sMixFuncs[4] = { @@ -149,6 +152,8 @@ void JASDriver::updateDSP() { JASPortCmd::execAllCommand(); DSPSyncCallback(); +#if !TARGET_PC + // Safety kill code? Our audio engine isn't consistent enough and hits this incorrectly. static u32 old_time = 0; static u32 history[10] = {0x000F4240}; u32 r28 = OSGetTick(); @@ -169,6 +174,7 @@ void JASDriver::updateDSP() { JASDSPChannel::killActiveChannel(); #endif } +#endif JASChannel::receiveBankDisposeMsg(); JASDSPChannel::updateAll(); @@ -271,11 +277,11 @@ u32 JASDriver::getSubFrames() { } u32 JASDriver::getDacSize() { - return sSubFrames * 0x50 * 2; + return sSubFrames * DSP_SUBFRAME_SIZE * 2; } u32 JASDriver::getFrameSamples() { - return sSubFrames * 0x50; + return sSubFrames * DSP_SUBFRAME_SIZE; } void JASDriver::mixMonoTrack(s16* buffer, u32 param_1, MixCallback param_2) { diff --git a/libs/JSystem/src/JAudio2/JASAramStream.cpp b/libs/JSystem/src/JAudio2/JASAramStream.cpp index 14f3221711..64ddfc467e 100644 --- a/libs/JSystem/src/JAudio2/JASAramStream.cpp +++ b/libs/JSystem/src/JAudio2/JASAramStream.cpp @@ -1,11 +1,12 @@ #include "JSystem/JSystem.h" // IWYU pragma: keep -#include "JSystem/JAudio2/JASAramStream.h" #include "JSystem/JAudio2/JASAiCtrl.h" +#include "JSystem/JAudio2/JASAramStream.h" +#include "JSystem/JAudio2/JASAudioThread.h" #include "JSystem/JAudio2/JASChannel.h" #include "JSystem/JAudio2/JASCriticalSection.h" -#include "JSystem/JAudio2/JASDriverIF.h" #include "JSystem/JAudio2/JASDSPInterface.h" +#include "JSystem/JAudio2/JASDriverIF.h" #include "JSystem/JAudio2/JASDvdThread.h" #include "JSystem/JKernel/JKRAram.h" #include "JSystem/JKernel/JKRSolidHeap.h" @@ -19,8 +20,23 @@ u32 JASAramStream::sBlockSize; u32 JASAramStream::sChannelMax; -bool struct_80451260; -bool struct_80451261; +bool dvdHasErrored; +bool hasErrored; + +#define PAUSE_REQUESTED 1 +#define PAUSE_DVD_ERROR 2 +#define PAUSE_UNDERFLOW 4 +#define PAUSE_OTHER_ERROR 8 + +// CMDs for mMainCommandQueue. +#define CMD_START 0 +#define CMD_STOP 1 // upper 16 bits of cmd contain oscillator direct release value. +#define CMD_PAUSE 2 +#define CMD_UNPAUSE 3 + +// CMDs for mLoadCommandQueue +#define CMD_PREPARE_FINISHED 4 +#define CMD_LOOP_END_LOADED 5 void JASAramStream::initSystem(u32 block_size, u32 channel_max) { JUT_ASSERT(66, block_size % 32 == 0); @@ -33,42 +49,46 @@ void JASAramStream::initSystem(u32 block_size, u32 channel_max) { if (sLoadThread == NULL) { sLoadThread = JASDvd::getThreadPointer(); } + + // Pretty sure this 0x20 corresponds to sizeof(BlockHeader). + // But that shouldn't be getting multiplied by the channel count. + // Bug in the original game, I guess? sReadBuffer = JKR_NEW_ARRAY_ARGS(u8, (block_size + 0x20) * channel_max, JASDram, 0x20); JUT_ASSERT(79, sReadBuffer); sBlockSize = block_size; sChannelMax = channel_max; - struct_80451260 = false; - struct_80451261 = false; + dvdHasErrored = false; + hasErrored = false; } } JASAramStream::JASAramStream() { - field_0x0a8 = NULL; - field_0x0ac = false; - field_0x0ad = false; - field_0x0ae = 0; + mPrimaryChannel = NULL; + mPrepareFinished = false; + mLoopEndLoaded = false; + mPauseFlags = 0; field_0x0b0 = 0; - field_0x0b4 = 0; - field_0x0b8 = 0; + mLastSamplesLeft = 0; + mReadSample = 0; field_0x0bc = 0; - field_0x0c0 = false; + mEndSetup = false; field_0x0c4 = 0; field_0x0c8 = 0.0f; - field_0x108 = 0; - field_0x10c = 0; + mRingEndIndex = 0; + mBlockRingIndex = 0; mBlock = 0; - field_0x114 = 0; - field_0x118 = 0; - field_0x12c = 0; - field_0x148 = 0; - field_0x14c = 0; + mIsCancelled = 0; + mPendingLoadTasks = 0; + mChannelUpdateFlags = 0; + mAramAddress = 0; + mAramSize = 0; mCallback = NULL; mCallbackData = NULL; - field_0x158 = 0; + mFormat = 0; mChannelNum = 0; mBufCount = 0; - field_0x160 = 0; - field_0x164 = 0; + mAramBlocksPerChannel = 0; + mSampleRate = 0; mLoop = false; mLoopStart = 0; mLoopEnd = 0; @@ -76,27 +96,27 @@ JASAramStream::JASAramStream() { mPitch = 1.0f; for (int i = 0; i < 6; i++) { mChannels[i] = NULL; - field_0x130[i] = 0; - field_0x13c[i] = 0; + mpLasts[i] = 0; + mpPenults[i] = 0; mChannelVolume[i] = 1.0f; mChannelPan[i] = 0.5f; mChannelFxMix[i] = 0.0f; mChannelDolby[i] = 0.0f; } for (int i = 0; i < 6; i++) { - field_0x1dc[i] = 0; + mMixConfig[i] = 0; } } -void JASAramStream::init(u32 param_0, u32 param_1, StreamCallback i_callback, void* i_callbackData) { +void JASAramStream::init(u32 aramAddress, u32 aramSize, StreamCallback i_callback, void* i_callbackData) { JUT_ASSERT(153, sReadBuffer != NULL); - field_0x148 = param_0; - field_0x14c = param_1; + mAramAddress = aramAddress; + mAramSize = aramSize; field_0x0c8 = 0.0f; - field_0x0ae = 0; - field_0x0ac = false; - field_0x0ad = false; - field_0x114 = 0; + mPauseFlags = 0; + mPrepareFinished = false; + mLoopEndLoaded = false; + mIsCancelled = 0; mChannelNum = 0; for (int i = 0; i < 6; i++) { mChannelVolume[i] = 1.0f; @@ -106,11 +126,11 @@ void JASAramStream::init(u32 param_0, u32 param_1, StreamCallback i_callback, vo } mVolume = 1.0f; mPitch = 1.0f; - field_0x1dc[0] = 0xffff; + mMixConfig[0] = 0xffff; mCallback = i_callback; mCallbackData = i_callbackData; - OSInitMessageQueue(&field_0x000, field_0x040, 0x10); - OSInitMessageQueue(&field_0x020, field_0x080, 4); + OSInitMessageQueue(&mMainCommandQueue, mMainCommandQueueArray, ARRAY_SIZEU(mMainCommandQueueArray)); + OSInitMessageQueue(&mLoadCommandQueue, mLoadCommandQueueArray, ARRAY_SIZEU(mLoadCommandQueueArray)); } bool JASAramStream::prepare(s32 param_0, int param_1) { @@ -124,9 +144,9 @@ bool JASAramStream::prepare(s32 param_0, int param_1) { } TaskData data; data.stream = this; - data.field_0x4 = field_0x14c; - data.field_0x8 = param_1; - if (!sLoadThread->sendCmdMsg(headerLoadTask, &data, 0xc)) { + data.param0 = mAramSize; + data.param1 = param_1; + if (!sLoadThread->sendCmdMsg(headerLoadTask, &data, sizeof(data))) { JUT_WARN(254, "%s", "sendCmdMsg headerLoadTask Failed"); JASDriver::rejectCallback(channelProcCallback, this); return false; @@ -135,24 +155,24 @@ bool JASAramStream::prepare(s32 param_0, int param_1) { } bool JASAramStream::start() { - if (!OSSendMessage(&field_0x000, (OSMessage)0, OS_MESSAGE_NOBLOCK)) { + if (!OSSendMessage(&mMainCommandQueue, (OSMessage)CMD_START, OS_MESSAGE_NOBLOCK)) { JUT_WARN(273, "%s", "OSSendMessage Failed") return false; } return true; } -bool JASAramStream::stop(u16 param_0) { - if (!OSSendMessage(&field_0x000, (OSMessage)(uintptr_t)(param_0 << 0x10 | 1), OS_MESSAGE_NOBLOCK)) { +bool JASAramStream::stop(u16 directRelease) { + if (!OSSendMessage(&mMainCommandQueue, (OSMessage)(uintptr_t)(directRelease << 0x10 | CMD_STOP), OS_MESSAGE_NOBLOCK)) { JUT_WARN(290, "%s", "OSSendMessage Failed"); return false; } return true; } -bool JASAramStream::pause(bool param_0) { - OSMessage msg = param_0 ? (OSMessage)2 : (OSMessage)3; - if (!OSSendMessage(&field_0x000, msg, OS_MESSAGE_NOBLOCK)) { +bool JASAramStream::pause(bool newPauseFlag) { + OSMessage msg = newPauseFlag ? (OSMessage)CMD_PAUSE : (OSMessage)CMD_UNPAUSE; + if (!OSSendMessage(&mMainCommandQueue, msg, OS_MESSAGE_NOBLOCK)) { JUT_WARN(308, "%s", "OSSendMessage Failed"); return false; } @@ -160,7 +180,7 @@ bool JASAramStream::pause(bool param_0) { } bool JASAramStream::cancel() { - field_0x114 = 1; + mIsCancelled = 1; if (!sLoadThread->sendCmdMsg(finishTask, this)) { JUT_WARN(326, "%s", "sendCmdMsg finishTask Failed"); return false; @@ -169,12 +189,12 @@ bool JASAramStream::cancel() { } u32 JASAramStream::getBlockSamples() const { - return field_0x158 == 0 ? (sBlockSize << 4) / 9 : sBlockSize >> 1; + return mFormat == STREAM_FORMAT_ADPCM4 ? (sBlockSize << 4) / 9 : sBlockSize >> 1; } void JASAramStream::headerLoadTask(void* i_data) { TaskData* data = (TaskData*)i_data; - data->stream->headerLoad(data->field_0x4, data->field_0x8); + data->stream->headerLoad(data->param0, data->param1); } void JASAramStream::firstLoadTask(void* i_data) { @@ -183,23 +203,23 @@ void JASAramStream::firstLoadTask(void* i_data) { if (!_this->load()) { return; } - if (data->field_0x8 > 0) { - data->field_0x8--; - if (data->field_0x8 == 0) { + if (data->param1 > 0) { + data->param1--; + if (data->param1 == 0) { if (!sLoadThread->sendCmdMsg(prepareFinishTask, _this)) { JUT_WARN(364, "%s", "sendCmdMsg prepareFinishTask Failed"); - struct_80451261 = true; + hasErrored = true; } } } - if (data->field_0x4 != 0) { - data->field_0x4--; - if (!sLoadThread->sendCmdMsg(firstLoadTask, data, 0xc)) { + if (data->param0 != 0) { + data->param0--; + if (!sLoadThread->sendCmdMsg(firstLoadTask, data, sizeof(*data))) { JUT_WARN(372, "%s", "sendCmdMsg firstLoadTask Failed"); - struct_80451261 = true; + hasErrored = true; } JASCriticalSection cs; - _this->field_0x118++; + _this->mPendingLoadTasks++; } } @@ -221,22 +241,22 @@ void JASAramStream::finishTask(void* i_this) { void JASAramStream::prepareFinishTask(void* i_this) { JASAramStream* _this = (JASAramStream*)i_this; - OSSendMessage(&_this->field_0x020, (OSMessage)4, OS_MESSAGE_BLOCK); + OSSendMessage(&_this->mLoadCommandQueue, (OSMessage)CMD_PREPARE_FINISHED, OS_MESSAGE_BLOCK); if (_this->mCallback != NULL) { _this->mCallback(CB_STOP, _this, _this->mCallbackData); } } -bool JASAramStream::headerLoad(u32 param_0, int param_1) { - if (struct_80451261) { +bool JASAramStream::headerLoad(u32 aramSize, int param_1) { + if (hasErrored) { return false; } - if (field_0x114 != 0) { + if (mIsCancelled != 0) { return false; } if (DVDReadPrio(&mDvdFileInfo, sReadBuffer, sizeof(Header), 0, 1) < 0) { JUT_WARN(420, "%s", "DVDReadPrio Failed"); - struct_80451261 = true; + hasErrored = true; return false; } Header* header = (Header*)sReadBuffer; @@ -245,45 +265,45 @@ bool JASAramStream::headerLoad(u32 param_0, int param_1) { JUT_ASSERT(428, header->bits == 16); JUT_ASSERT(429, header->channels <= sChannelMax); JUT_ASSERT(430, header->block_size == sBlockSize); - field_0x158 = header->format; + mFormat = header->format; mChannelNum = header->channels; - field_0x164 = header->field_0x10; + mSampleRate = header->mSampleRate; mLoop = header->loop != 0; mLoopStart = header->loop_start; mLoopEnd = header->loop_end; - mVolume = header->field_0x28 / 127.0f; - field_0x118 = 0; + mVolume = header->mVolume / 127.0f; + mPendingLoadTasks = 0; mBlock = 0; - field_0x10c = 0; - field_0x160 = (param_0 / sBlockSize) / header->channels; - mBufCount = field_0x160; + mBlockRingIndex = 0; + mAramBlocksPerChannel = (aramSize / sBlockSize) / header->channels; + mBufCount = mAramBlocksPerChannel; JUT_ASSERT(445, mBufCount > 0); mBufCount--; if (mBufCount < 3) { JUT_WARN(449, "%s", "Too few Buffer-Size"); } - field_0x108 = mBufCount; + mRingEndIndex = mBufCount; u32 local_2c = (mLoopEnd - 1) / getBlockSamples(); if (local_2c <= mBufCount && mLoop) { JUT_WARN(458, "%s", "Too few samples for Loop-buffer"); } - if (param_1 < 0 || param_1 > field_0x108) { - param_1 = field_0x108; + if (param_1 < 0 || param_1 > mRingEndIndex) { + param_1 = mRingEndIndex; } - if (field_0x114 != 0) { + if (mIsCancelled != 0) { return false; } TaskData data; data.stream = this; - data.field_0x4 = field_0x108 - 1; - data.field_0x8 = param_1; - if (!sLoadThread->sendCmdMsg(firstLoadTask, &data, 0xc)) { + data.param0 = mRingEndIndex - 1; + data.param1 = param_1; + if (!sLoadThread->sendCmdMsg(firstLoadTask, &data, sizeof(data))) { JUT_WARN(472, "%s", "sendCmdMsg firstLoadTask Failed"); - struct_80451261 = true; + hasErrored = true; return false; } JASCriticalSection cs; - field_0x118++; + mPendingLoadTasks++; return true; } @@ -291,12 +311,12 @@ bool JASAramStream::headerLoad(u32 param_0, int param_1) { bool JASAramStream::load() { { JASCriticalSection cs; - field_0x118--; + mPendingLoadTasks--; } - if (struct_80451261) { + if (hasErrored) { return false; } - if (field_0x114 != 0) { + if (mIsCancelled != 0) { return false; } u32 loop_end_block = (mLoopEnd - 1) / getBlockSamples(); @@ -311,31 +331,31 @@ bool JASAramStream::load() { } if (DVDReadPrio(&mDvdFileInfo, sReadBuffer, size, offset, 1) < 0) { JUT_WARN(507, "%s", "DVDReadPrio Failed"); - struct_80451261 = true; + hasErrored = true; return false; } BlockHeader* bhead = (BlockHeader*)sReadBuffer; JUT_ASSERT(512, bhead->tag == 'BLCK'); - if (field_0x114 != 0) { + if (mIsCancelled != 0) { return false; } - u32 sp08 = field_0x148 + field_0x10c * sBlockSize; + u32 blockBaseOffset = mAramAddress + mBlockRingIndex * sBlockSize; for (int i = 0; i < mChannelNum; i++) { (void)i; // Fakematch? It seems the only way to get the bhead->field_0x4 load in the right order is // with a pointer cast on its address in one of the two places it is read, but not both. - if (!JKRMainRamToAram(sReadBuffer + *(u32*)&bhead->field_0x4 * i + sizeof(BlockHeader), - sp08 + sBlockSize * field_0x160 * i, - bhead->field_0x4, EXPAND_SWITCH_UNKNOWN0, 0, NULL, -1, NULL)) { + if (!JKRMainRamToAram(sReadBuffer + bhead->mSize * i + sizeof(BlockHeader), + blockBaseOffset + sBlockSize * mAramBlocksPerChannel * i, + bhead->mSize, EXPAND_SWITCH_UNKNOWN0, 0, NULL, -1, NULL)) { JUT_WARN(522, "%s", "JKRMainRamToAram Failed"); - struct_80451261 = 1; + hasErrored = 1; return false; } } - field_0x10c++; - if (field_0x10c >= field_0x108) { + mBlockRingIndex++; + if (mBlockRingIndex >= mRingEndIndex) { u32 r28 = mBlock; - r28 += field_0x108 - 1; + r28 += mRingEndIndex - 1; if (mLoop) { JUT_ASSERT(537, loop_start_block < loop_end_block); while (r28 > loop_end_block) { @@ -344,16 +364,16 @@ bool JASAramStream::load() { } } if (r28 == loop_end_block || r28 + 2 == loop_end_block) { - field_0x108 = field_0x160; - OSSendMessage(&field_0x020, (OSMessage)5, OS_MESSAGE_BLOCK); + mRingEndIndex = mAramBlocksPerChannel; + OSSendMessage(&mLoadCommandQueue, (OSMessage)CMD_LOOP_END_LOADED, OS_MESSAGE_BLOCK); } else { - field_0x108 = field_0x160 - 1; + mRingEndIndex = mAramBlocksPerChannel - 1; } for (int i = 0; i < mChannelNum; i++) { - field_0x130[i] = (s16)bhead->field_0x8[i].field_0x0; - field_0x13c[i] = (s16)bhead->field_0x8[i].field_0x2; + mpLasts[i] = (s16)bhead->mAdpcmContinuationData[i].mpLast; + mpPenults[i] = (s16)bhead->mAdpcmContinuationData[i].mpPenult; } - field_0x10c = 0; + mBlockRingIndex = 0; } mBlock++; if (mBlock > loop_end_block && mLoop) { @@ -371,7 +391,7 @@ s32 JASAramStream::dvdErrorCheck(void* param_0) { s32 status = DVDGetDriveStatus(); switch (status) { case DVD_STATE_END: - struct_80451260 = false; + dvdHasErrored = false; break; case DVD_STATE_BUSY: break; @@ -385,7 +405,7 @@ s32 JASAramStream::dvdErrorCheck(void* param_0) { case DVD_STATE_RETRY: case DVD_STATE_FATAL_ERROR: default: - struct_80451260 = true; + dvdHasErrored = true; break; } return 0; @@ -397,98 +417,125 @@ void JASAramStream::channelCallback(u32 i_callbackType, JASChannel* i_channel, stream->updateChannel(i_callbackType, i_channel, i_dspChannel); } +#define CHANNEL_UPDATE_SAMPLES_LEFT 1 +#define CHANNEL_UPDATE_LOOP_START 2 +#define CHANNEL_UPDATE_END_SAMPLE 4 +#define CHANNEL_UPDATE_LOOP_FLAG 8 + + void JASAramStream::updateChannel(u32 i_callbackType, JASChannel* i_channel, JASDsp::TChannel* i_dspChannel) { u32 block_samples = getBlockSamples(); switch (i_callbackType) { case JASChannel::CB_START: - if (field_0x0a8 == NULL) { - field_0x0a8 = i_channel; - field_0x0b4 = block_samples * mBufCount; - field_0x0b8 = 0; + if (mPrimaryChannel == NULL) { + mPrimaryChannel = i_channel; + mLastSamplesLeft = block_samples * mBufCount; + mReadSample = 0; field_0x0b0 = 0; field_0x0bc = (mLoopEnd - 1) / block_samples; - field_0x0c0 = 0; + mEndSetup = 0; field_0x0c4 = 0; - field_0x12c = 0; + mChannelUpdateFlags = 0; } break; case JASChannel::CB_PLAY: - if (i_dspChannel->field_0x008 == 0) { - if (i_channel == field_0x0a8) { - field_0x12c = 0; - u32 sp28 = i_dspChannel->field_0x074 + i_dspChannel->field_0x064; - if (sp28 <= field_0x0b4) { - field_0x0b8 += field_0x0b4 - sp28; + if (i_dspChannel->mResetFlag == 0) { + if (i_channel == mPrimaryChannel) { + /* + if (JASAudioThread::snIntCount == 1) { + OSReportForceEnableOn(); + OSReport("mSamplesLeft: %08d, mAramStreamPosition: %08d\n", i_dspChannel->mSamplesLeft, i_dspChannel->mAramStreamPosition); + } + */ + + mChannelUpdateFlags = 0; + u32 adjustedSamplesLeft = i_dspChannel->mSamplesLeft + i_dspChannel->mSamplesPerBlock; + if (adjustedSamplesLeft <= mLastSamplesLeft) { + mReadSample += mLastSamplesLeft - adjustedSamplesLeft; } else { - if (!field_0x0c0) { - field_0x0b8 += field_0x0b4; - field_0x0b8 += block_samples * mBufCount - sp28; + // The DSP has looped. + + if (!mEndSetup) { + // Just looping the ring buffer, data continues as normal. + mReadSample += mLastSamplesLeft; + mReadSample += block_samples * mBufCount - adjustedSamplesLeft; } else { - field_0x0b8 += field_0x0b4; - field_0x0b8 += block_samples * mBufCount - sp28 - - i_dspChannel->field_0x110; - field_0x0b8 -= mLoopEnd; - field_0x0b8 += mLoopStart; - i_dspChannel->field_0x110 = 0; - field_0x120 = 0; - field_0x12c |= 2; + // We hit the actual file loop position. + mReadSample += mLastSamplesLeft; + mReadSample += block_samples * mBufCount - adjustedSamplesLeft + - i_dspChannel->mLoopStartSample; + mReadSample -= mLoopEnd; + mReadSample += mLoopStart; + i_dspChannel->mLoopStartSample = 0; + mUpdateLoopStartSample = 0; + mChannelUpdateFlags |= CHANNEL_UPDATE_LOOP_START; +#if !TARGET_PC // The variable assigned here is never used. if (field_0x0c4 < 0xffffffff) { field_0x0c4 += 1; } - field_0x0c0 = false; +#endif + mEndSetup = false; } } - if (field_0x0b8 > mLoopEnd) { + if (mReadSample > mLoopEnd) { JUT_WARN(686, "%s", "mReadSample > mLoopEnd"); - struct_80451261 = true; + hasErrored = true; } + +#if !TARGET_PC // The variable assigned here is never used. f32 fvar1 = field_0x0c4; fvar1 *= mLoopEnd - mLoopStart; if (field_0x0c4 < 0xffffffff) { - fvar1 += field_0x0b8; + fvar1 += mReadSample; } - fvar1 /= field_0x164; + fvar1 /= mSampleRate; field_0x0c8 = fvar1; - if (field_0x0b8 + 400 >= mLoopEnd && !field_0x0c0) { +#endif + + if (mReadSample + 400 >= mLoopEnd && !mEndSetup) { if (mLoop) { + // File needs to loop. Adjust loop start position + // (out of the normal ring buffer behavior). u32 uvar5 = field_0x0bc + 1; if (uvar5 >= mBufCount) { uvar5 = 0; } - i_dspChannel->field_0x110 = mLoopStart % block_samples + i_dspChannel->mLoopStartSample = mLoopStart % block_samples + uvar5 * block_samples; - field_0x120 = i_dspChannel->field_0x110; - field_0x12c |= 2; + mUpdateLoopStartSample = i_dspChannel->mLoopStartSample; + mChannelUpdateFlags |= CHANNEL_UPDATE_LOOP_START; } else { - i_dspChannel->field_0x102 = 0; - field_0x128 = 0; - field_0x12c |= 8; + // File doesn't need to loop, just unset loop flag + // and let the DSP finish naturally. + i_dspChannel->mLoopFlag = 0; + mUpdateLoopFlag = 0; + mChannelUpdateFlags |= CHANNEL_UPDATE_LOOP_FLAG; } int sp20 = field_0x0bc * block_samples + mLoopEnd % block_samples; - i_dspChannel->field_0x074 -= block_samples * mBufCount - sp20; - field_0x11c = i_dspChannel->field_0x074; - field_0x12c |= 1; + i_dspChannel->mSamplesLeft -= block_samples * mBufCount - sp20; + mUpdateSamplesLeft = i_dspChannel->mSamplesLeft; + mChannelUpdateFlags |= CHANNEL_UPDATE_SAMPLES_LEFT; field_0x0bc += (mLoopEnd - 1) / block_samples - mLoopStart / block_samples + 1; - field_0x0c0 = true; + mEndSetup = true; } - u32 uvar4 = i_dspChannel->field_0x070 - i_channel->field_0x104; + u32 uvar4 = i_dspChannel->mAramStreamPosition - i_channel->mWaveAramAddress; if (uvar4 != 0) { uvar4--; } - u32 sp18 = uvar4 / sBlockSize; + u32 blockCount = uvar4 / sBlockSize; u32 sp14 = (mLoopEnd - 1) / getBlockSamples(); - if (sp18 != field_0x0b0) { - bool cmp = sp18 < field_0x0b0; - while (sp18 != field_0x0b0) { + if (blockCount != field_0x0b0) { + bool cmp = blockCount < field_0x0b0; + while (blockCount != field_0x0b0) { if (!sLoadThread->sendCmdMsg(loadToAramTask, this)) { - JUT_WARN(741, "sendCmdMsg Failed %d %d (%d %d)", i_dspChannel->field_0x070, i_channel->field_0x104, sp18, field_0x0b0); - struct_80451261 = true; + JUT_WARN(741, "sendCmdMsg Failed %d %d (%d %d)", i_dspChannel->mAramStreamPosition, i_channel->mWaveAramAddress, blockCount, field_0x0b0); + hasErrored = true; break; } { JASCriticalSection cs; - field_0x118++; + mPendingLoadTasks++; } field_0x0b0++; if (field_0x0b0 >= mBufCount) { @@ -497,65 +544,65 @@ void JASAramStream::updateChannel(u32 i_callbackType, JASChannel* i_channel, } if (cmp) { field_0x0bc -= mBufCount; - if (field_0x0ad) { - if (!field_0x0c0) { - i_dspChannel->field_0x074 += block_samples; - field_0x11c = i_dspChannel->field_0x074; - field_0x12c |= 1; + if (mLoopEndLoaded) { + if (!mEndSetup) { + i_dspChannel->mSamplesLeft += block_samples; + mUpdateSamplesLeft = i_dspChannel->mSamplesLeft; + mChannelUpdateFlags |= CHANNEL_UPDATE_SAMPLES_LEFT; } - i_dspChannel->field_0x114 += block_samples; - field_0x124 = i_dspChannel->field_0x114; - field_0x12c |= 4; - mBufCount = field_0x160; - field_0x0ad = false; + i_dspChannel->mEndSample += block_samples; + mUpdateEndSample = i_dspChannel->mEndSample; + mChannelUpdateFlags |= CHANNEL_UPDATE_END_SAMPLE; + mBufCount = mAramBlocksPerChannel; + mLoopEndLoaded = false; } else { - if (mBufCount != field_0x160 - 1) { - mBufCount = field_0x160 - 1; - i_dspChannel->field_0x114 -= block_samples; - field_0x124 = i_dspChannel->field_0x114; - field_0x12c |= 4; - if (!field_0x0c0) { - i_dspChannel->field_0x074 -= block_samples; - field_0x11c = i_dspChannel->field_0x074; - field_0x12c |= 1; + if (mBufCount != mAramBlocksPerChannel - 1) { + mBufCount = mAramBlocksPerChannel - 1; + i_dspChannel->mEndSample -= block_samples; + mUpdateEndSample = i_dspChannel->mEndSample; + mChannelUpdateFlags |= CHANNEL_UPDATE_END_SAMPLE; + if (!mEndSetup) { + i_dspChannel->mSamplesLeft -= block_samples; + mUpdateSamplesLeft = i_dspChannel->mSamplesLeft; + mChannelUpdateFlags |= CHANNEL_UPDATE_SAMPLES_LEFT; } } } } } else { - if (field_0x118 == 0 && !struct_80451260) { - field_0x0ae &= ~2; - field_0x0ae &= ~4; + if (mPendingLoadTasks == 0 && !dvdHasErrored) { + mPauseFlags &= ~PAUSE_DVD_ERROR; + mPauseFlags &= ~PAUSE_UNDERFLOW; } } - field_0x0b4 = i_dspChannel->field_0x074 + i_dspChannel->field_0x064; - if (field_0x118 >= field_0x160 - 2) { + mLastSamplesLeft = i_dspChannel->mSamplesLeft + i_dspChannel->mSamplesPerBlock; + if (mPendingLoadTasks >= mAramBlocksPerChannel - 2) { JUT_WARN_DEVICE(810, 1, "%s", "buffer under error"); - field_0x0ae |= (u8)4; + mPauseFlags |= (u8)PAUSE_UNDERFLOW; } } else { - if (field_0x12c & 1) { - i_dspChannel->field_0x074 = field_0x11c; + if (mChannelUpdateFlags & CHANNEL_UPDATE_SAMPLES_LEFT) { + i_dspChannel->mSamplesLeft = mUpdateSamplesLeft; } - if (field_0x12c & 2) { - i_dspChannel->field_0x110 = field_0x120; + if (mChannelUpdateFlags & CHANNEL_UPDATE_LOOP_START) { + i_dspChannel->mLoopStartSample = mUpdateLoopStartSample; } - if (field_0x12c & 4) { - i_dspChannel->field_0x114 = field_0x124; + if (mChannelUpdateFlags & CHANNEL_UPDATE_END_SAMPLE) { + i_dspChannel->mEndSample = mUpdateEndSample; } - if (field_0x12c & 8) { - i_dspChannel->field_0x102 = field_0x128; + if (mChannelUpdateFlags & CHANNEL_UPDATE_LOOP_FLAG) { + i_dspChannel->mLoopFlag = mUpdateLoopFlag; } } int ch = 0; - for (; ch < 6; ch++) { + for (; ch < CHANNEL_MAX; ch++) { if (i_channel == mChannels[ch]) { break; } } JUT_ASSERT(834, ch < CHANNEL_MAX); - i_dspChannel->field_0x104 = (s16)field_0x130[ch]; - i_dspChannel->field_0x106 = (s16)field_0x13c[ch]; + i_dspChannel->mpLast = (s16)mpLasts[ch]; + i_dspChannel->mpPenult = (s16)mpPenults[ch]; } break; case JASChannel::CB_STOP: @@ -568,57 +615,57 @@ void JASAramStream::updateChannel(u32 i_callbackType, JASChannel* i_channel, } } if (!open_channel) { - field_0x114 = 1; + mIsCancelled = 1; if (!sLoadThread->sendCmdMsg(finishTask, this)) { JUT_WARN(854, "%s", "sendCmdMsg finishTask Failed"); - struct_80451261 = true; + hasErrored = true; return; } } break; } - i_channel->setPauseFlag(field_0x0ae != 0); + i_channel->setPauseFlag(mPauseFlags != 0); } s32 JASAramStream::channelProc() { OSMessage msg; - while (OSReceiveMessage(&field_0x020, &msg, OS_MESSAGE_NOBLOCK)) { + while (OSReceiveMessage(&mLoadCommandQueue, &msg, OS_MESSAGE_NOBLOCK)) { switch ((uintptr_t)msg) { - case 4: - field_0x0ac = true; + case CMD_PREPARE_FINISHED: + mPrepareFinished = true; break; - case 5: - field_0x0ad = true; + case CMD_LOOP_END_LOADED: + mLoopEndLoaded = true; break; } } - if (!field_0x0ac) { + if (!mPrepareFinished) { return 0; } - while (OSReceiveMessage(&field_0x000, &msg, OS_MESSAGE_NOBLOCK)) { + while (OSReceiveMessage(&mMainCommandQueue, &msg, OS_MESSAGE_NOBLOCK)) { switch ((uintptr_t)msg & 0xff) { - case 0: + case CMD_START: channelStart(); break; - case 1: + case CMD_STOP: channelStop(JSUHiHalf((uintptr_t)msg)); break; - case 2: - field_0x0ae |= 1; + case CMD_PAUSE: + mPauseFlags |= PAUSE_REQUESTED; break; - case 3: - field_0x0ae &= ~1; + case CMD_UNPAUSE: + mPauseFlags &= ~PAUSE_REQUESTED; break; } } - if (struct_80451261) { - field_0x0ae |= 8; + if (hasErrored) { + mPauseFlags |= PAUSE_OTHER_ERROR; } - if (struct_80451260) { - field_0x0ae |= 2; + if (dvdHasErrored) { + mPauseFlags |= PAUSE_DVD_ERROR; } for (int i = 0; i < mChannelNum; i++) { @@ -646,44 +693,44 @@ static JASOscillator::Point const OSC_RELEASE_TABLE[2] = { static JASOscillator::Data const OSC_ENV = {0, 1.0f, NULL, OSC_RELEASE_TABLE, 1.0f, 0.0f}; void JASAramStream::channelStart() { - u8 r31; - switch (field_0x158) { - case 0: - r31 = 0; + u8 format; + switch (mFormat) { + case STREAM_FORMAT_ADPCM4: + format = WAVE_FORMAT_ADPCM4; break; - case 1: - r31 = 3; + case STREAM_FORMAT_PCM16: + format = WAVE_FORMAT_PCM16; break; } for (int i = 0; i < mChannelNum; i++) { JASWaveInfo wave_info; - wave_info.field_0x00 = r31; - wave_info.field_0x02 = 0xff; - wave_info.field_0x10 = 0; - wave_info.field_0x14 = mBufCount * getBlockSamples(); - wave_info.field_0x18 = wave_info.field_0x14; - wave_info.field_0x1c = 0; - wave_info.field_0x1e = 0; + wave_info.mWaveFormat = format; + wave_info.mLoopFlag = 0xff; + wave_info.mLoopStartSample = 0; + wave_info.mLoopEndSample = mBufCount * getBlockSamples(); + wave_info.mSampleCount = wave_info.mLoopEndSample; + wave_info.mpLast = 0; + wave_info.mpPenult = 0; // probably a fake match, this should be set in the JASWaveInfo constructor static u32 const one = 1; wave_info.field_0x20 = &one; JASChannel* jc = JKR_NEW JASChannel(channelCallback, this); JUT_ASSERT(963, jc); jc->setPriority(0x7f7f); - for (u32 j = 0; j < 6; j++) { - jc->setMixConfig(j, field_0x1dc[j]); + for (u32 j = 0; j < DSP_OUTPUT_CHANNELS; j++) { + jc->setMixConfig(j, mMixConfig[j]); } - jc->setInitPitch(field_0x164 / JASDriver::getDacRate()); + jc->setInitPitch(mSampleRate / JASDriver::getDacRate()); jc->setOscInit(0, &OSC_ENV); - jc->field_0xdc.field_0x4 = wave_info; - jc->field_0x104 = field_0x148 + sBlockSize * field_0x160 * i; - jc->field_0xdc.field_0x0 = 0; + jc->field_0xdc.mWaveInfo = wave_info; + jc->mWaveAramAddress = mAramAddress + sBlockSize * mAramBlocksPerChannel * i; + jc->field_0xdc.mChannelType = 0; int ret = jc->playForce(); JUT_ASSERT(977, ret); JUT_ASSERT_MSG(979, mChannels[i] == NULL, "channelStart for already playing channel"); mChannels[i] = jc; } - field_0x0a8 = NULL; + mPrimaryChannel = NULL; } diff --git a/libs/JSystem/src/JAudio2/JASAudioReseter.cpp b/libs/JSystem/src/JAudio2/JASAudioReseter.cpp index 4d4f3517c1..46853d03e7 100644 --- a/libs/JSystem/src/JAudio2/JASAudioReseter.cpp +++ b/libs/JSystem/src/JAudio2/JASAudioReseter.cpp @@ -47,7 +47,7 @@ s32 JASAudioReseter::checkDone() const { s32 JASAudioReseter::calc() { if (field_0x0==0) { - for (size_t i = 0; i<64; i++) { + for (size_t i = 0; igetStatus() == 0) { handle->drop(); diff --git a/libs/JSystem/src/JAudio2/JASAudioThread.cpp b/libs/JSystem/src/JAudio2/JASAudioThread.cpp index fc926b3bb5..fa476d1cb4 100644 --- a/libs/JSystem/src/JAudio2/JASAudioThread.cpp +++ b/libs/JSystem/src/JAudio2/JASAudioThread.cpp @@ -21,17 +21,8 @@ JASAudioThread::JASAudioThread(int stackSize, int msgCount, u32 threadPriority) OSInitThreadQueue(&sThreadQueue); } -#if TARGET_PC -bool JASAudioThread::sThreadInitComplete = false; -OSMutex JASAudioThread::sThreadInitCompleteMutex; -OSCond JASAudioThread::sThreadInitCompleteCond; -#endif - void JASAudioThread::create(s32 threadPriority) { -#if TARGET_PC - OSInitMutex(&sThreadInitCompleteMutex); - OSInitCond(&sThreadInitCompleteCond); -#endif + OSPanic(__FILE__, __LINE__, "JASAudioThread does not work on PC!"); #if PLATFORM_GCN const int size = 0x1400; @@ -64,12 +55,18 @@ private: BOOL mInterrupts; }; +#if !TARGET_PC class JASChannel { u8 filler[0x108]; }; +#else +// You don't want to know how long I spent debugging this. +#include "JSystem/JAudio2/JASChannel.h" +#endif // NONMATCHING location of JASPoolAllocObject_MultiThreaded void* JASAudioThread::run() { +#if !TARGET_PC OSInitFastCast(); JASDriver::initAI(DMACallback); JASDsp::boot(DSPCallback); @@ -79,13 +76,6 @@ void* JASAudioThread::run() { JASPoolAllocObject_MultiThreaded::newMemPool(0x48); JASDriver::startDMA(); -#if TARGET_PC - OSLockMutex(&sThreadInitCompleteMutex); - sThreadInitComplete = true; - OSUnlockMutex(&sThreadInitCompleteMutex); - OSSignalCond(&sThreadInitCompleteCond); -#endif - OSMessage msg; while (true) { msg = waitMessageBlock(); @@ -126,6 +116,9 @@ void* JASAudioThread::run() { JUT_PANIC(152, "AUDIO THREAD INVALID MESSAGE\n"); } } +#else + return 0; +#endif } void JASAudioThread::DMACallback() { @@ -139,6 +132,7 @@ void JASAudioThread::DMACallback() { } void JASAudioThread::DSPCallback(void*) { +#if !TARGET_PC JASAudioThread* pAudioThread = getInstance(); JUT_ASSERT(184, pAudioThread); while (DSPCheckMailFromDSP() == 0) { } @@ -155,4 +149,5 @@ void JASAudioThread::DSPCallback(void*) { JASDsp::finishWork(mail); } } +#endif } diff --git a/libs/JSystem/src/JAudio2/JASBNKParser.cpp b/libs/JSystem/src/JAudio2/JASBNKParser.cpp index b9f010ad60..ddab6d2e38 100644 --- a/libs/JSystem/src/JAudio2/JASBNKParser.cpp +++ b/libs/JSystem/src/JAudio2/JASBNKParser.cpp @@ -23,7 +23,7 @@ JASBasicBank* JASBNKParser::createBasicBank(void const* stream, JKRHeap* heap) { u32 free_size = heap->getFreeSize(); TFileHeader* filep = (TFileHeader*)stream; - JUT_ASSERT(59, filep->id == 'IBNK'); + JUT_ASSERT(59, filep->mMagic == 'IBNK'); JASBasicBank* bank = NULL; switch (filep->mVersion) { case 0: @@ -79,11 +79,11 @@ JASBasicBank* JASBNKParser::Ver1::createBasicBank(void const* stream, JKRHeap* h JUT_ASSERT(155, op->id == 'Osci'); JASOscillator::Data* data = &osc_data[i]; data->mTarget = op->mTarget; - data->_04 = op->_08; + data->mRate = op->mRate; data->mScale = op->mScale; - data->_14 = op->_18; - data->mTable = (JASOscillator::Point*)(envt + op->mTableOffset); - data->rel_table = (JASOscillator::Point*)(envt + op->_10); + data->mVertex = op->mVertex; + data->mTable = (JASOscillator::Point*)(envt + op->mAttackEnvelopeOffset); + data->rel_table = (JASOscillator::Point*)(envt + op->mReleaseEnvelopeOffset); } TListChunk* list = list_chunk; JUT_ASSERT(172, list->count <= JASBank::PRG_OSC); @@ -128,8 +128,10 @@ JASBasicBank* JASBNKParser::Ver1::createBasicBank(void const* stream, JKRHeap* h case 'Perc': { JASDrumSet* drump = JKR_NEW_ARGS (heap, 0) JASDrumSet; JUT_ASSERT(264, drump != NULL); + #if PLATFORM_SHIELD u32 pmap_count = data[1]; JUT_ASSERT(268, pmap_count <= 128); + #endif u32 count = *data++; drump->newPercArray(count, heap); for (int j = 0; j < count; j++) { @@ -137,8 +139,10 @@ JASBasicBank* JASBNKParser::Ver1::createBasicBank(void const* stream, JKRHeap* h if (offset != 0) { JASDrumSet::TPerc* percp = JKR_NEW_ARGS (heap, 0) JASDrumSet::TPerc; JUT_ASSERT(277, percp); + #if PLATFORM_SHIELD u32 type = data[0]; JUT_ASSERT(282, type == 'Pmap'); + #endif BE(u32)* ptr = (BE(u32)*)((intptr_t)stream + offset); TPercData* perc_data = (TPercData*)(ptr + 1); percp->setVolume(perc_data->mVolume); @@ -203,7 +207,7 @@ JASBasicBank* JASBNKParser::Ver0::createBasicBank(void const* stream, JKRHeap* h osc = JKR_NEW_ARGS (heap, 0) JASOscillator::Data; JUT_ASSERT(386, osc != NULL); osc->mTarget = tosc->mTarget; - osc->_04 = tosc->field_0x4; + osc->mRate = tosc->field_0x4; JASOscillator::Point* points = tosc->mPointOffset.ptr(header); if (points != NULL) { @@ -230,7 +234,7 @@ JASBasicBank* JASBNKParser::Ver0::createBasicBank(void const* stream, JKRHeap* h } osc->mScale = tosc->mScale; - osc->_14 = tosc->field_0x14; + osc->mVertex = tosc->field_0x14; instp->setOsc(osc_idx, osc); } @@ -312,7 +316,7 @@ JASOscillator::Data* JASBNKParser::Ver0::findOscPtr(JASBasicBank* bank, THeader JASOscillator::Point const* JASBNKParser::Ver0::getOscTableEndPtr(JASOscillator::Point const* points) { const JASOscillator::Point* ptr = points; while(true) { - s16 tmp = ptr->_0; + s16 tmp = ptr->mEnvelopeMode; ptr++; if (tmp > 10) { break; diff --git a/libs/JSystem/src/JAudio2/JASBank.cpp b/libs/JSystem/src/JAudio2/JASBank.cpp index 7d4fb86514..29ebe11cb5 100644 --- a/libs/JSystem/src/JAudio2/JASBank.cpp +++ b/libs/JSystem/src/JAudio2/JASBank.cpp @@ -42,13 +42,13 @@ JASChannel* JASBank::noteOn(JASBank const* param_0, int param_1, u8 param_2, u8 return NULL; } channel->setPriority(param_4); - channel->field_0xdc.field_0x4 = *waveInfo; - channel->field_0x104 = wavePtr; - channel->field_0xdc.field_0x0 = stack_60.field_0x1c; + channel->field_0xdc.mWaveInfo = *waveInfo; + channel->mWaveAramAddress = wavePtr; + channel->field_0xdc.mChannelType = stack_60.field_0x1c; channel->setBankDisposeID(param_0); - channel->setInitPitch(stack_60.mPitch * (waveInfo->field_0x04 / JASDriver::getDacRate())); + channel->setInitPitch(stack_60.mPitch * (waveInfo->mSampleRate / JASDriver::getDacRate())); if (stack_60.field_0x1e == 0) { - channel->setKey(param_2 - waveInfo->field_0x01); + channel->setKey(param_2 - waveInfo->mBaseKey); } channel->setInitVolume(stack_60.mVolume); channel->setVelocity(param_3); @@ -79,10 +79,10 @@ JASChannel* JASBank::noteOnOsc(int param_0, u8 param_1, u8 param_2, u16 param_3, return NULL; } channel->setPriority(param_3); - channel->field_0x104 = param_0; - channel->field_0xdc.field_0x0 = 2; + channel->mOscillatorSomething = param_0; + channel->field_0xdc.mChannelType = 2; channel->setInitPitch(16736.016f / JASDriver::getDacRate()); - channel->setKey(param_1 - channel->field_0xdc.field_0x4.field_0x01); + channel->setKey(param_1 - channel->field_0xdc.mWaveInfo.mBaseKey); channel->setVelocity(param_2); channel->setOscInit(0, &OSC_ENV); if (!channel->play()) { diff --git a/libs/JSystem/src/JAudio2/JASBasicWaveBank.cpp b/libs/JSystem/src/JAudio2/JASBasicWaveBank.cpp index 5387238a56..9170e59ed1 100644 --- a/libs/JSystem/src/JAudio2/JASBasicWaveBank.cpp +++ b/libs/JSystem/src/JAudio2/JASBasicWaveBank.cpp @@ -50,7 +50,7 @@ void JASBasicWaveBank::incWaveTable(JASBasicWaveBank::TWaveGroup const* param_0) if (!handle->mHeap) { handle->mHeap = ¶m_0->mHeap; handle->field_0x4.field_0x20 = ¶m_0->_48; - handle->field_0x4.field_0x08 = param_0->mCtrlWaveArray[i].field_0x4; + handle->field_0x4.mOffsetStart = param_0->mCtrlWaveArray[i].field_0x4; } } } @@ -64,7 +64,7 @@ void JASBasicWaveBank::decWaveTable(JASBasicWaveBank::TWaveGroup const* param_0) if (handle->mHeap == ¶m_0->mHeap) { handle->mHeap = NULL; handle->field_0x4.field_0x20 = &mNoLoad; - handle->field_0x4.field_0x08 = -1; + handle->field_0x4.mOffsetStart = -1; } } } @@ -86,9 +86,9 @@ void JASBasicWaveBank::setWaveInfo(JASBasicWaveBank::TWaveGroup* wgrp, int index JUT_ASSERT(206, index >= 0); mWaveTable[param_2].field_0x4 = param_3; mWaveTable[param_2].field_0x4.field_0x20 = &mNoLoad; - mWaveTable[param_2].field_0x4.field_0x08 = -1; + mWaveTable[param_2].field_0x4.mOffsetStart = -1; wgrp->mCtrlWaveArray[index].field_0x0 = param_2; - wgrp->mCtrlWaveArray[index].field_0x4 = param_3.field_0x08; + wgrp->mCtrlWaveArray[index].field_0x4 = param_3.mOffsetStart; } JASBasicWaveBank::TWaveGroup::TWaveGroup() { @@ -131,5 +131,5 @@ intptr_t JASBasicWaveBank::TWaveHandle::getWavePtr() const { if (base == 0) { return 0; } - return (intptr_t)base + field_0x4.field_0x08; + return (intptr_t)base + field_0x4.mOffsetStart; } diff --git a/libs/JSystem/src/JAudio2/JASCalc.cpp b/libs/JSystem/src/JAudio2/JASCalc.cpp index 79d9cb500f..906fee2c3d 100644 --- a/libs/JSystem/src/JAudio2/JASCalc.cpp +++ b/libs/JSystem/src/JAudio2/JASCalc.cpp @@ -132,7 +132,11 @@ void JASCalc::bzero(void* dest, u32 size) { } } +#if AVOID_UB +s16 const JASCalc::CUTOFF_TO_IIR_TABLE[129][4] = { +#else s16 const JASCalc::CUTOFF_TO_IIR_TABLE[128][4] = { +#endif 0x0F5C, 0x0A3D, 0x4665, 0x1E73, 0x0F5E, 0x0A3D, 0x4664, 0x1E73, 0x0F63, 0x0A3C, 0x4661, 0x1E71, @@ -261,6 +265,10 @@ s16 const JASCalc::CUTOFF_TO_IIR_TABLE[128][4] = { 0x7C7A, 0x0052, 0x0233, 0x00F4, 0x7E3B, 0x0029, 0x011B, 0x007A, 0x7FFF, 0x0000, 0x0000, 0x0000, +#if AVOID_UB + // Game OOB reads this in some cases. + 0,0,0,0 +#endif }; // currently required because of missing functions diff --git a/libs/JSystem/src/JAudio2/JASChannel.cpp b/libs/JSystem/src/JAudio2/JASChannel.cpp index 8e81ef3e86..61fe80a098 100644 --- a/libs/JSystem/src/JAudio2/JASChannel.cpp +++ b/libs/JSystem/src/JAudio2/JASChannel.cpp @@ -31,7 +31,7 @@ JASChannel::JASChannel(Callback i_callback, void* i_callbackData) : mKeySweepCount(0), mSkipSamples(0) { - field_0xdc.field_0x0 = 0; + field_0xdc.mChannelType = 0; field_0x104 = 0; mMixConfig[0].whole = 0x150; mMixConfig[1].whole = 0x210; @@ -171,12 +171,12 @@ void JASChannel::updateEffectorParam(JASDsp::TChannel* i_channel, u16* i_mixerVo f32 pan = 0.5f; f32 dolby = 0.0f; switch (JASDriver::getOutputMode()) { - case 0: + case JAS_OUTPUT_MONO: break; - case 1: + case JAS_OUTPUT_STEREO: pan = calcPan(&pan_vector); break; - case 2: + case JAS_OUTPUT_SURROUND: pan = calcPan(&pan_vector); dolby = calcEffect(&dolby_vector); break; @@ -229,7 +229,7 @@ s32 JASChannel::initialUpdateDSPChannel(JASDsp::TChannel* i_channel) { mCallback(CB_START, this, i_channel, mCallbackData); } - if (field_0xdc.field_0x4.field_0x20[0] == 0) { + if (field_0xdc.mWaveInfo.field_0x20[0] == 0) { JUT_WARN_DEVICE(346, 2, "%s", "Lost wave data while playing"); mDspCh->free(); mDspCh = NULL; @@ -245,19 +245,19 @@ s32 JASChannel::initialUpdateDSPChannel(JASDsp::TChannel* i_channel) { return -1; } - switch (field_0xdc.field_0x0) { + switch (field_0xdc.mChannelType) { case 0: - i_channel->setWaveInfo(field_0xdc.field_0x4, field_0x104, mSkipSamples); + i_channel->setWaveInfo(field_0xdc.mWaveInfo, mWaveAramAddress, mSkipSamples); break; case 2: - i_channel->setOscInfo(field_0x104); + i_channel->setOscInfo(mOscillatorSomething); break; } - for (u8 i = 0; i < 6; i++) { + for (u8 i = 0; i < DSP_OUTPUT_CHANNELS; i++) { MixConfig mix_config = mMixConfig[i]; u32 output_mode = JASDriver::getOutputMode(); - if (output_mode == 0) { + if (output_mode == JAS_OUTPUT_MONO) { switch (mix_config.parts.upper) { case 8: mix_config.parts.upper = 11; @@ -266,7 +266,7 @@ s32 JASChannel::initialUpdateDSPChannel(JASDsp::TChannel* i_channel) { mix_config.parts.upper = 2; break; } - } else if (output_mode == 1 && mix_config.parts.upper == 8) { + } else if (output_mode == JAS_OUTPUT_STEREO && mix_config.parts.upper == 8) { mix_config.parts.upper = 11; } i_channel->setBusConnect(i, mix_config.parts.upper); @@ -281,9 +281,9 @@ s32 JASChannel::initialUpdateDSPChannel(JASDsp::TChannel* i_channel) { } mVibrate.resetCounter(); mTremolo.resetCounter(); - u16 mixer_volume[6]; + u16 mixer_volume[DSP_OUTPUT_CHANNELS]; updateEffectorParam(i_channel, mixer_volume, effect_params); - for (u8 i = 0; i < 6; i++) { + for (u8 i = 0; i < DSP_OUTPUT_CHANNELS; i++) { i_channel->setMixerInitVolume(i, mixer_volume[i]); } @@ -307,7 +307,7 @@ s32 JASChannel::updateDSPChannel(JASDsp::TChannel* i_channel) { mCallback(CB_PLAY, this, i_channel, mCallbackData); } - if (field_0xdc.field_0x4.field_0x20[0] == 0) { + if (field_0xdc.mWaveInfo.field_0x20[0] == 0) { JUT_WARN_DEVICE(456, 2, "%s","Lost wave data while playing"); mDspCh->free(); mDspCh = NULL; @@ -378,18 +378,18 @@ s32 JASChannel::updateDSPChannel(JASDsp::TChannel* i_channel) { return 0; } -void JASChannel::updateAutoMixer(JASDsp::TChannel* i_channel, f32 param_1, f32 param_2, - f32 param_3, f32 param_4) { - if (JASDriver::getOutputMode() == 0) { - param_1 *= 0.707f; +void JASChannel::updateAutoMixer(JASDsp::TChannel* i_channel, f32 volume, f32 pan, + f32 fxmix, f32 dolby) { + if (JASDriver::getOutputMode() == JAS_OUTPUT_MONO) { + volume *= 0.707f; } - param_1 = JASCalc::clamp01(param_1); + volume = JASCalc::clamp01(volume); - u16 r31 = param_1 * JASDriver::getChannelLevel_dsp(); - u8 r30 = param_2 * 127.5f; - u8 r29 = param_4 * 127.5f; - u8 r28 = param_3 * 127.5f; - i_channel->setAutoMixer(r31, r30, r29, r28, 0); + u16 dspVolume = volume * JASDriver::getChannelLevel_dsp(); + u8 dspPan = pan * 127.5f; + u8 dspDolby = dolby * 127.5f; + u8 dspFxMix = fxmix * 127.5f; + i_channel->setAutoMixer(dspVolume, dspPan, dspDolby, dspFxMix, 0); } void JASChannel::updateMixer(f32 i_volume, f32 i_pan, f32 i_fxmix, f32 i_dolby, u16* i_volumeOut) { @@ -429,7 +429,7 @@ void JASChannel::updateMixer(f32 i_volume, f32 i_pan, f32 i_fxmix, f32 i_dolby, volume *= scale; break; default: - if (JASDriver::getOutputMode() == 0) { + if (JASDriver::getOutputMode() == JAS_OUTPUT_MONO) { volume *= scale; } else { volume *= JMASinRadian(scale * JGeometry::TUtil::PI() * 0.5f); @@ -470,8 +470,8 @@ void JASChannel::updateMixer(f32 i_volume, f32 i_pan, f32 i_fxmix, f32 i_dolby, case 6: volume *= scale; break; - default: - if (JASDriver::getOutputMode() == 0) { + default: // 0, 1, 4, 5, 8-15 + if (JASDriver::getOutputMode() == JAS_OUTPUT_MONO) { volume *= scale; } else { volume *= JMASinRadian(scale * JGeometry::TUtil::PI() * 0.5f); diff --git a/libs/JSystem/src/JAudio2/JASDSPChannel.cpp b/libs/JSystem/src/JAudio2/JASDSPChannel.cpp index 1c5171082e..62c983248c 100644 --- a/libs/JSystem/src/JAudio2/JASDSPChannel.cpp +++ b/libs/JSystem/src/JAudio2/JASDSPChannel.cpp @@ -10,7 +10,7 @@ JASDSPChannel::JASDSPChannel() : mStatus(STATUS_INACTIVE), mPriority(-1), mFlags(0), - field_0xc(0), + mUpdateCounter(0), mCallback(NULL), mCallbackData(NULL), mChannel(NULL) @@ -42,9 +42,9 @@ void JASDSPChannel::drop() { } void JASDSPChannel::initAll() { - sDspChannels = JKR_NEW_ARRAY_ARGS(JASDSPChannel, 0x40, JASDram, 0x20); + sDspChannels = JKR_NEW_ARRAY_ARGS(JASDSPChannel, DSP_CHANNELS, JASDram, 0x20); JUT_ASSERT(102, sDspChannels); - for (int i = 0; i < 0x40; i++) { + for (int i = 0; i < DSP_CHANNELS; i++) { sDspChannels[i].mChannel = JASDsp::getDSPHandle(i); } } @@ -56,7 +56,7 @@ JASDSPChannel* JASDSPChannel::alloc(u8 i_priority, Callback i_callback, void* i_ } channel->drop(); channel->mPriority = i_priority; - channel->field_0xc = 0; + channel->mUpdateCounter = 0; channel->mCallback = i_callback; channel->mCallbackData = i_callbackData; return channel; @@ -70,7 +70,7 @@ JASDSPChannel* JASDSPChannel::allocForce(u8 i_priority, Callback i_callback, voi channel->mStatus = STATUS_INACTIVE; channel->drop(); channel->mPriority = i_priority; - channel->field_0xc = 0; + channel->mUpdateCounter = 0; channel->mCallback = i_callback; channel->mCallbackData = i_callbackData; return channel; @@ -83,16 +83,16 @@ void JASDSPChannel::setPriority(u8 i_priority) { JASDSPChannel* JASDSPChannel::getLowestChannel(int i_priority) { s16 best_priority = 0xff; int best_index = -1; - int best_unknown = 0; - for (int i = 0; i < 0x40; i++) { + int best_updateCounter = 0; + for (int i = 0; i < DSP_CHANNELS; i++) { JASDSPChannel* channel = &sDspChannels[i]; s16 priority = channel->mPriority; if (priority < 0) { return &sDspChannels[i]; } if (priority <= i_priority && priority <= best_priority) { - if (priority != best_priority || channel->field_0xc > best_unknown) { - best_unknown = channel->field_0xc; + if (priority != best_priority || channel->mUpdateCounter > best_updateCounter) { + best_updateCounter = channel->mUpdateCounter; best_index = i; best_priority = priority; } @@ -107,14 +107,14 @@ JASDSPChannel* JASDSPChannel::getLowestChannel(int i_priority) { JASDSPChannel* JASDSPChannel::getLowestActiveChannel() { s16 best_priority = 0xff; int best_index = -1; - int best_unknown = 0; - for (int i = 0; i < 0x40; i++) { + int best_updateCounter = 0; + for (int i = 0; i < DSP_CHANNELS; i++) { JASDSPChannel* channel = &sDspChannels[i]; if (channel->mStatus == STATUS_ACTIVE) { s16 priority = channel->mPriority; if (priority < 0x7f && priority <= best_priority) { - if (priority != best_priority || channel->field_0xc > best_unknown) { - best_unknown = channel->field_0xc; + if (priority != best_priority || channel->mUpdateCounter > best_updateCounter) { + best_updateCounter = channel->mUpdateCounter; best_index = i; best_priority = priority; } @@ -195,7 +195,7 @@ void JASDSPChannel::updateProc() { mChannel->playStop(); mChannel->flush(); } else { - field_0xc++; + mUpdateCounter++; if (flush) { mChannel->flush(); } @@ -205,7 +205,7 @@ void JASDSPChannel::updateProc() { } void JASDSPChannel::updateAll() { - for (u32 i = 0; i < 0x40; i++) { + for (u32 i = 0; i < DSP_CHANNELS; i++) { if ((i & 0xf) == 0 && i != 0) { JASDsp::releaseHalt((i - 1) >> 4); } @@ -230,8 +230,8 @@ JASDSPChannel* JASDSPChannel::getHandle(u32 i_index) { u32 JASDSPChannel::getNumUse() { u32 count = 0; - for (int i = 0; i < 0x40; i++) { - if (sDspChannels[i].mStatus == 0) { + for (int i = 0; i < DSP_CHANNELS; i++) { + if (sDspChannels[i].mStatus == STATUS_ACTIVE) { count++; } } @@ -240,8 +240,8 @@ u32 JASDSPChannel::getNumUse() { u32 JASDSPChannel::getNumFree() { u32 count = 0; - for (int i = 0; i < 0x40; i++) { - if (sDspChannels[i].mStatus == 1) { + for (int i = 0; i < DSP_CHANNELS; i++) { + if (sDspChannels[i].mStatus == STATUS_INACTIVE) { count++; } } @@ -250,8 +250,8 @@ u32 JASDSPChannel::getNumFree() { u32 JASDSPChannel::getNumBreak() { u32 count = 0; - for (int i = 0; i < 0x40; i++) { - if (sDspChannels[i].mStatus == 2) { + for (int i = 0; i < DSP_CHANNELS; i++) { + if (sDspChannels[i].mStatus == STATUS_DROP) { count++; } } diff --git a/libs/JSystem/src/JAudio2/JASDSPInterface.cpp b/libs/JSystem/src/JAudio2/JASDSPInterface.cpp index ba2d110436..49ca691011 100644 --- a/libs/JSystem/src/JAudio2/JASDSPInterface.cpp +++ b/libs/JSystem/src/JAudio2/JASDSPInterface.cpp @@ -50,6 +50,10 @@ void JASDsp::boot(void (*param_0)(void*)) { } void JASDsp::releaseHalt(u32 param_0) { +#if TARGET_PC + // Dusk DSP does not work incrementally. + return; +#endif DSPReleaseHalt2(param_0); } @@ -72,8 +76,8 @@ f32 JASDsp::getDSPMixerLevel() { return sDSPVolume; } -JASDsp::TChannel* JASDsp::getDSPHandle(int param_0) { - return CH_BUF + param_0; +JASDsp::TChannel* JASDsp::getDSPHandle(int index) { + return CH_BUF + index; } JASDsp::TChannel* JASDsp::getDSPHandleNc(int param_0) { @@ -87,12 +91,12 @@ void JASDsp::setFilterTable(s16* param_0, s16* param_1, u32 param_2) { } void JASDsp::flushBuffer() { - DCFlushRange(CH_BUF, sizeof(TChannel) * 64); + DCFlushRange(CH_BUF, sizeof(TChannel) * DSP_CHANNELS); DCFlushRange(FX_BUF, sizeof(FxBuf) * 4); } void JASDsp::invalChannelAll() { - DCInvalidateRange(CH_BUF, sizeof(TChannel) * 64); + DCInvalidateRange(CH_BUF, sizeof(TChannel) * DSP_CHANNELS); } u8 const ATTRIBUTE_ALIGN(32) JASDsp::DSPADPCM_FILTER[64] = { @@ -426,16 +430,16 @@ u32 const ATTRIBUTE_ALIGN(32) JASDsp::DSPRES_FILTER[320] = { }; void JASDsp::initBuffer() { - CH_BUF = JKR_NEW_ARRAY_ARGS(TChannel, 64, JASDram, 0x20); + CH_BUF = JKR_NEW_ARRAY_ARGS(TChannel, DSP_CHANNELS, JASDram, 0x20); JUT_ASSERT(354, CH_BUF); FX_BUF = JKR_NEW_ARRAY_ARGS(FxBuf, 4, JASDram, 0x20); JUT_ASSERT(356, FX_BUF); - JASCalc::bzero(CH_BUF, 0x6000); + JASCalc::bzero(CH_BUF, sizeof(TChannel) * DSP_CHANNELS); JASCalc::bzero(FX_BUF, sizeof(FxBuf) * 4); for (u8 i = 0; i < 4; i++) { setFXLine(i, NULL, NULL); } - DsetupTable(0x40, uintptr_t(CH_BUF), uintptr_t(&DSPRES_FILTER), uintptr_t(&DSPADPCM_FILTER), uintptr_t(FX_BUF)); + DsetupTable(DSP_CHANNELS, uintptr_t(CH_BUF), uintptr_t(&DSPRES_FILTER), uintptr_t(&DSPADPCM_FILTER), uintptr_t(FX_BUF)); flushBuffer(); } @@ -501,8 +505,8 @@ void JASDsp::TChannel::init() { mIsFinished = 0; mForcedStop = 0; mIsActive = 0; - field_0x058 = 0; - field_0x068 = 0; + mAutoMixerBeenSet = 0; + mSamplePosition = 0; initFilter(); } @@ -510,7 +514,7 @@ void JASDsp::TChannel::playStart() { JUT_ASSERT(508, dspMutex); field_0x10c = 0; field_0x060 = 0; - field_0x008 = 1; + mResetFlag = 1; field_0x066 = 0; int i; for (i = 0; i < 4; i++) { @@ -549,41 +553,41 @@ bool JASDsp::TChannel::isFinish() const { return mIsFinished != 0; } -void JASDsp::TChannel::setWaveInfo(JASWaveInfo const& param_0, u32 param_1, u32 param_2) { +void JASDsp::TChannel::setWaveInfo(JASWaveInfo const& waveInfo, u32 aramAddress, u32 skipSamples) { int i; JUT_ASSERT(610, dspMutex); - field_0x118 = param_1; + mWaveAramAddress = aramAddress; static const u8 COMP_BLOCKSAMPLES[8] = {0x10, 0x10, 0x01, 0x01, 0x01, 0x10, 0x10, 0x01}; - field_0x064 = COMP_BLOCKSAMPLES[param_0.field_0x00]; + mSamplesPerBlock = COMP_BLOCKSAMPLES[waveInfo.mWaveFormat]; static const u8 COMP_BLOCKBYTES[8] = {0x09, 0x05, 0x08, 0x10, 0x01, 0x01, 0x01, 0x01}; - field_0x100 = COMP_BLOCKBYTES[param_0.field_0x00]; - field_0x068 = 0; - if (field_0x100 >= 4) { - field_0x11c = param_0.field_0x18; - field_0x102 = param_0.field_0x02; - if (field_0x102) { - if (param_2 == 1) { - param_2 = param_0.field_0x10; + mBytesPerBlock = COMP_BLOCKBYTES[waveInfo.mWaveFormat]; + mSamplePosition = 0; + if (mBytesPerBlock >= 4) { + mSampleCount = waveInfo.mSampleCount; + mLoopFlag = waveInfo.mLoopFlag; + if (mLoopFlag) { + if (skipSamples == 1) { + skipSamples = waveInfo.mLoopStartSample; } - field_0x110 = param_0.field_0x10; - field_0x114 = param_0.field_0x14; - field_0x104 = param_0.field_0x1c; - field_0x106 = param_0.field_0x1e; + mLoopStartSample = waveInfo.mLoopStartSample; + mEndSample = waveInfo.mLoopEndSample; + mpLast = waveInfo.mpLast; + mpPenult = waveInfo.mpPenult; } else { - field_0x114 = field_0x11c; + mEndSample = mSampleCount; } - if (param_2 && field_0x114 > param_2) { - switch (param_0.field_0x00) { - case 0: - case 1: - field_0x068 = param_2; - field_0x118 += param_2 * field_0x100 >> 4; - field_0x110 -= param_2; - field_0x114 -= param_2; + if (skipSamples && mEndSample > skipSamples) { + switch (waveInfo.mWaveFormat) { + case WAVE_FORMAT_ADPCM4: + case WAVE_FORMAT_ADPCM2: + mSamplePosition = skipSamples; + mWaveAramAddress += skipSamples * mBytesPerBlock >> 4; + mLoopStartSample -= skipSamples; + mEndSample -= skipSamples; break; - case 2: - case 3: - field_0x068 = param_2; + case WAVE_FORMAT_PCM8: + case WAVE_FORMAT_PCM16: + mSamplePosition = skipSamples; break; } } @@ -595,28 +599,27 @@ void JASDsp::TChannel::setWaveInfo(JASWaveInfo const& param_0, u32 param_1, u32 void JASDsp::TChannel::setOscInfo(u32 param_0) { JUT_ASSERT(671, dspMutex); - field_0x118 = 0; - field_0x064 = 16; - field_0x100 = param_0; + mWaveAramAddress = 0; + mSamplesPerBlock = 16; + mBytesPerBlock = param_0; } void JASDsp::TChannel::initAutoMixer() { JUT_ASSERT(688, dspMutex); - if (field_0x058) { - field_0x054 = field_0x056; + if (mAutoMixerBeenSet) { + mAutoMixerInitVolume = mAutoMixerVolume; } else { - field_0x054 = 0; - field_0x058 = 1; + mAutoMixerInitVolume = 0; + mAutoMixerBeenSet = 1; } } -void JASDsp::TChannel::setAutoMixer(u16 param_0, u8 param_1, u8 param_2, u8 param_3, - u8 param_4) { +void JASDsp::TChannel::setAutoMixer(u16 volume, u8 pan, u8 dolby, u8 fxMix, u8) { JUT_ASSERT(709, dspMutex); - field_0x050 = (param_1 << 8) | param_2; - field_0x052 = param_3 << 8 | param_3 << 1; - field_0x056 = param_0; - field_0x058 = 1; + mAutoMixerPanDolby = (pan << 8) | dolby; + mAutoMixerFxMix = fxMix << 8 | fxMix << 1; + mAutoMixerVolume = volume; + mAutoMixerBeenSet = 1; } void JASDsp::TChannel::setPitch(u16 param_0) { @@ -627,21 +630,20 @@ void JASDsp::TChannel::setPitch(u16 param_0) { mPitch = param_0; } -void JASDsp::TChannel::setMixerInitVolume(u8 param_0, s16 param_1) { +void JASDsp::TChannel::setMixerInitVolume(u8 outputChannel, s16 volume) { JUT_ASSERT(798, dspMutex); - u16* tmp = field_0x010[param_0]; - tmp[2] = param_1; - tmp[1] = param_1; - tmp[3] = 0; + OutputChannelConfig& cfg = mOutputChannels[outputChannel]; + cfg.mCurrentVolume = volume; + cfg.mTargetVolume = volume; + cfg.mVolumeProgress = 0; } -void JASDsp::TChannel::setMixerVolume(u8 param_0, s16 param_1) { - u16* tmp; +void JASDsp::TChannel::setMixerVolume(u8 outputChannel, s16 volume) { JUT_ASSERT(841, dspMutex); if (mForcedStop == 0) { - tmp = field_0x010[param_0]; - tmp[1] = param_1; - tmp[3] &= 0xff; + OutputChannelConfig& cfg = mOutputChannels[outputChannel]; + cfg.mTargetVolume = volume; + cfg.mVolumeProgress &= 0xff; } } @@ -699,16 +701,25 @@ void JASDsp::TChannel::setDistFilter(s16 param_0) { iir_filter_params[4] = param_0; } -void JASDsp::TChannel::setBusConnect(u8 param_0, u8 param_1) { +void JASDsp::TChannel::setBusConnect(u8 outputChannel, u8 param_1) { JUT_ASSERT(973, dspMutex); - u16* tmp = field_0x010[param_0]; + OutputChannelConfig& tmp = mOutputChannels[outputChannel]; +#if AVOID_UB + if (param_1 == 255) { + // Seems to happen for "dolby mode" where the mix config is 0xFFFF. + // Probably UB without side effect in the base game as afaict the DSP + // doesn't look at mix config when "dolby mode" is active. + return; + } + JUT_ASSERT(0, param_1 < 12); +#endif static u16 const connect_table[12] = { 0x0000, 0x0D00, 0x0D60, 0x0DC0, 0x0E20, 0x0E80, 0x0EE0, 0x0CA0, 0x0F40, 0x0FA0, 0x0B00, 0x09A0, }; u16 r30 = 0; r30 = connect_table[param_1]; - tmp[0] = r30; + tmp.mBusConnect = r30; } u16 DSP_CreateMap2(u32 param_0) { diff --git a/libs/JSystem/src/JAudio2/JASDriverIF.cpp b/libs/JSystem/src/JAudio2/JASDriverIF.cpp index 2c9f305b61..7d602a8856 100644 --- a/libs/JSystem/src/JAudio2/JASDriverIF.cpp +++ b/libs/JSystem/src/JAudio2/JASDriverIF.cpp @@ -23,10 +23,10 @@ f32 JASDriver::getDSPLevel() { return JASDsp::getDSPMixerLevel(); } -u32 JASDriver::JAS_SYSTEM_OUTPUT_MODE = 0x00000001; +u32 JASDriver::JAS_SYSTEM_OUTPUT_MODE = JAS_OUTPUT_STEREO; -void JASDriver::setOutputMode(u32 param_0) { - JAS_SYSTEM_OUTPUT_MODE = param_0; +void JASDriver::setOutputMode(u32 mode) { + JAS_SYSTEM_OUTPUT_MODE = mode; } u32 JASDriver::getOutputMode() { diff --git a/libs/JSystem/src/JAudio2/JASDrumSet.cpp b/libs/JSystem/src/JAudio2/JASDrumSet.cpp index a7a483fe29..8c8736451d 100644 --- a/libs/JSystem/src/JAudio2/JASDrumSet.cpp +++ b/libs/JSystem/src/JAudio2/JASDrumSet.cpp @@ -49,11 +49,11 @@ bool JASDrumSet::getParam(int key, int param_1, JASInstParam* param_2) const { static JASOscillator::Data osc; osc.mTarget = 0; - osc._04 = 1.0f; + osc.mRate = 1.0f; osc.mTable = NULL; osc.rel_table = NULL; osc.mScale = 1.0f; - osc._14 = 0.0f; + osc.mVertex = 0.0f; static JASOscillator::Data* oscp = &osc; diff --git a/libs/JSystem/src/JAudio2/JASOscillator.cpp b/libs/JSystem/src/JAudio2/JASOscillator.cpp index 4073af7424..f4bf2ade6f 100644 --- a/libs/JSystem/src/JAudio2/JASOscillator.cpp +++ b/libs/JSystem/src/JAudio2/JASOscillator.cpp @@ -4,9 +4,9 @@ JASOscillator::JASOscillator() { mData = NULL; - _14 = 0; + mCurPoint = 0; mDirectRelease = 0; - _18 = 0; + mEnvelopeMode = 0; _1C = 0; _04 = _08 = _10 = _0C = 0.0f; } @@ -17,7 +17,7 @@ void JASOscillator::initStart(JASOscillator::Data const* data) { _04 = 0.0f; _08 = 0.0f; _0C = 0.0f; - _14 = 0; + mCurPoint = 0; mDirectRelease = 0; if (!data) { _1C = 0; @@ -30,8 +30,8 @@ void JASOscillator::initStart(JASOscillator::Data const* data) { return; } - _10 = mData->mTable[0]._4 / 32768.0f; - _18 = mData->mTable[0]._0; + _10 = mData->mTable[0].mValue / 32768.0f; + mEnvelopeMode = mData->mTable[0].mEnvelopeMode; _1C = 1; } @@ -44,13 +44,13 @@ void JASOscillator::incCounter(f32 param_0) { case 1: break; } - _04 += param_0 * mData->_04; + _04 += param_0 * mData->mRate; update(); } f32 JASOscillator::getValue() const { JUT_ASSERT(120, mData); - return _08 * mData->mScale + mData->_14; + return _08 * mData->mScale + mData->mVertex; } void JASOscillator::release() { @@ -63,8 +63,8 @@ void JASOscillator::release() { _04 = 0.0f; _0C = _08; _10 = 0.0f; - _14 = 0; - _18 = (mDirectRelease >> 14) & 3; + mCurPoint = 0; + mEnvelopeMode = (mDirectRelease >> 14) & 3; _1C = 4; update(); return; @@ -74,9 +74,9 @@ void JASOscillator::release() { JUT_ASSERT(157, mData->rel_table != NULL); _04 = 0.0f; _0C = _08; - _10 = mData->rel_table[0]._4 / 32768.0f; - _14 = 0; - _18 = mData->rel_table[0]._0; + _10 = mData->rel_table[0].mValue / 32768.0f; + mCurPoint = 0; + mEnvelopeMode = mData->rel_table[0].mEnvelopeMode; } _1C = 3; @@ -104,31 +104,31 @@ void JASOscillator::update() { return; } - while (_04 >= psVar1[_14]._2) { - _04 -= psVar1[_14]._2; + while (_04 >= psVar1[mCurPoint].mTime) { + _04 -= psVar1[mCurPoint].mTime; _08 = _10; - _14++; + mCurPoint++; _0C = _08; - const BE(s16)* ps = &psVar1[_14]._0; - s16 r26 = ps[0]; - switch(r26) { - case 0xf: + const Point* ps = &psVar1[mCurPoint]; + s16 mode = ps->mEnvelopeMode; + switch(mode) { + case ENVELOPE_STOP: _1C = 0; return; - case 0xe: + case ENVELOPE_HOLD: _1C = 2; return; - case 0xd: - _14 = ps[2]; + case ENVELOPE_LOOP: + mCurPoint = ps->mValue; break; default: - _18 = r26; - _10 = ps[2] / 32768.0f; + mEnvelopeMode = mode; + _10 = ps->mValue / 32768.0f; break; } } - updateCurrentValue(psVar1[_14]._2); + updateCurrentValue(psVar1[mCurPoint].mTime); } f32 const JASOscillator::sCurveTableLinear[17] = { @@ -163,7 +163,7 @@ static f32* table_list[4] = { }; void JASOscillator::updateCurrentValue(f32 param_0) { - f32* table = table_list[_18]; + f32* table = table_list[mEnvelopeMode]; f32 fVar1 = 16.0f * (_04 / param_0); u32 index = (u32) fVar1; f32 fVar3 = (fVar1 - index); diff --git a/libs/JSystem/src/JAudio2/JASSeqCtrl.cpp b/libs/JSystem/src/JAudio2/JASSeqCtrl.cpp index 044f3873f2..a4e4a4b441 100644 --- a/libs/JSystem/src/JAudio2/JASSeqCtrl.cpp +++ b/libs/JSystem/src/JAudio2/JASSeqCtrl.cpp @@ -34,9 +34,9 @@ void JASSeqCtrl::init() { field_0x51 = 0; } -void JASSeqCtrl::start(void* param_0, u32 param_1) { - mReader.init(param_0); - mReader.jump(param_1); +void JASSeqCtrl::start(void* base, u32 offset) { + mReader.init(base); + mReader.jump(offset); } int JASSeqCtrl::tickProc(JASTrack* param_0) { diff --git a/libs/JSystem/src/JAudio2/JASSeqParser.cpp b/libs/JSystem/src/JAudio2/JASSeqParser.cpp index bb80e583c2..7b417f2c82 100644 --- a/libs/JSystem/src/JAudio2/JASSeqParser.cpp +++ b/libs/JSystem/src/JAudio2/JASSeqParser.cpp @@ -950,7 +950,7 @@ s32 JASSeqParser::parseNoteOn(JASTrack* param_0, u8 param_1) { return 0; } -s32 JASSeqParser::parseCommand(JASTrack* param_0, u8 cmd, u16 param_2) { +s32 JASSeqParser::parseCommand(JASTrack* param_0, u8 cmd, u16 parameterTypesOverride) { JASSeqCtrl* seqCtrl = param_0->getSeqCtrl(); CmdInfo* cmdInfo = NULL; if (cmd != 0xb0) { @@ -959,32 +959,32 @@ s32 JASSeqParser::parseCommand(JASTrack* param_0, u8 cmd, u16 param_2) { } else { cmdInfo = &sExtCmdInfo[seqCtrl->readByte() & 0xff]; } - u16 r28 = (u16)cmdInfo->field_0xe; - r28 |= param_2; - u32 stack_28[8]; - for (int i = 0; i < cmdInfo->field_0xc; i++, r28 >>= 2) { - int r27 = 0; - switch (r28 & 3) { + u16 parameterTypes = (u16)cmdInfo->mParameterTypes; + parameterTypes |= parameterTypesOverride; + u32 args[8]; + for (int i = 0; i < cmdInfo->mParameterCount; i++, parameterTypes >>= 2) { + int value = 0; + switch (parameterTypes & 3) { case 0: - r27 = (u8)seqCtrl->readByte(); + value = (u8)seqCtrl->readByte(); break; case 1: - r27 = (u16)seqCtrl->read16(); + value = (u16)seqCtrl->read16(); break; case 2: - r27 = seqCtrl->read24(); + value = seqCtrl->read24(); break; case 3: - r27 = readReg(param_0, (u8)seqCtrl->readByte()); + value = readReg(param_0, (u8)seqCtrl->readByte()); break; } - stack_28[i] = r27; + args[i] = value; } - s32 (JASSeqParser::*ptr)(JASTrack*, u32*) = cmdInfo->field_0x0; + s32 (JASSeqParser::*ptr)(JASTrack*, u32*) = cmdInfo->mHandler; if (!ptr) { return 0; } - return execCommand(param_0, ptr, cmdInfo->field_0xc, stack_28); + return execCommand(param_0, ptr, cmdInfo->mParameterCount, args); } s32 JASSeqParser::parseRegCommand(JASTrack* param_0, int param_1) { @@ -1004,7 +1004,9 @@ s32 JASSeqParser::parseRegCommand(JASTrack* param_0, int param_1) { } s32 JASSeqParser::parse(JASTrack* param_0) { - u32 r31 = param_0->getSeqCtrl()->readByte(); + JASSeqCtrl* ctrl = param_0->getSeqCtrl(); + u32 base = ctrl->mReader.mCurPos - ctrl->mReader.mBase; + u32 r31 = ctrl->readByte(); s32 r30 = 0; if ((r31 & 0x80) == 0) { r30 = parseNoteOn(param_0, r31); diff --git a/libs/JSystem/src/JAudio2/JASSeqReader.cpp b/libs/JSystem/src/JAudio2/JASSeqReader.cpp index c259c57d40..459c2edeee 100644 --- a/libs/JSystem/src/JAudio2/JASSeqReader.cpp +++ b/libs/JSystem/src/JAudio2/JASSeqReader.cpp @@ -8,81 +8,81 @@ #include "JSystem/JAudio2/JASSeqReader.h" void JASSeqReader::init() { - field_0x00 = 0; - field_0x04 = 0; - field_0x08 = 0; + mBase = 0; + mCurPos = 0; + mCurStackDepth = 0; - for (int i = 0; i < 8; i++) { - field_0x0c[i] = NULL; - field_0x2c[i] = 0; + for (int i = 0; i < JAS_SEQ_STACK_SIZE; i++) { + mReturnAddr[i] = NULL; + mLoopCount[i] = 0; } } -void JASSeqReader::init(void* param_0) { - field_0x00 = (u8*)param_0; - field_0x04 = field_0x00; - field_0x08 = 0; +void JASSeqReader::init(void* base) { + mBase = (u8*)base; + mCurPos = mBase; + mCurStackDepth = 0; - for (int i = 0; i < 8; i++) { - field_0x0c[i] = NULL; - field_0x2c[i] = 0; + for (int i = 0; i < JAS_SEQ_STACK_SIZE; i++) { + mReturnAddr[i] = NULL; + mLoopCount[i] = 0; } } bool JASSeqReader::call(u32 param_0) { - if (field_0x08 >= 8) { + if (mCurStackDepth >= JAS_SEQ_STACK_SIZE) { JUT_WARN(42, "%s", "Cannot exec call command"); return false; } - field_0x0c[field_0x08++] = (u16*)field_0x04; - field_0x04 = field_0x00 + param_0; + mReturnAddr[mCurStackDepth++] = (u16*)mCurPos; + mCurPos = mBase + param_0; return true; } bool JASSeqReader::loopStart(u32 param_0) { - if (8 <= field_0x08) { + if (JAS_SEQ_STACK_SIZE <= mCurStackDepth) { JUT_WARN(53, "%s", "Cannot exec loopStart command"); return false; } - field_0x0c[field_0x08] = (u16*)field_0x04; - field_0x2c[field_0x08++] = param_0; + mReturnAddr[mCurStackDepth] = (u16*)mCurPos; + mLoopCount[mCurStackDepth++] = param_0; return true; } bool JASSeqReader::loopEnd() { - if (field_0x08 == 0) { + if (mCurStackDepth == 0) { JUT_WARN(65, "%s", "cannot loopE for call-stack is NULL"); return false; } - u16 tmp = field_0x2c[field_0x08 - 1]; + u16 tmp = mLoopCount[mCurStackDepth - 1]; if (tmp != 0) { tmp--; } if (!tmp) { - field_0x08--; + mCurStackDepth--; return true; } - field_0x2c[field_0x08 - 1] = tmp; - field_0x04 = (u8*)field_0x0c[field_0x08 - 1]; + mLoopCount[mCurStackDepth - 1] = tmp; + mCurPos = (u8*)mReturnAddr[mCurStackDepth - 1]; return true; } bool JASSeqReader::ret() { - if (field_0x08 == 0) { + if (mCurStackDepth == 0) { return false; } - field_0x04 = (u8*)field_0x0c[--field_0x08]; + mCurPos = (u8*)mReturnAddr[--mCurStackDepth]; return true; } diff --git a/libs/JSystem/src/JAudio2/JASSimpleWaveBank.cpp b/libs/JSystem/src/JAudio2/JASSimpleWaveBank.cpp index 8bfcc2c460..52935324d8 100644 --- a/libs/JSystem/src/JAudio2/JASSimpleWaveBank.cpp +++ b/libs/JSystem/src/JAudio2/JASSimpleWaveBank.cpp @@ -44,7 +44,7 @@ intptr_t JASSimpleWaveBank::TWaveHandle::getWavePtr() const { if (base == NULL) { return 0; } - return (intptr_t)base + mWaveInfo.field_0x08; + return (intptr_t)base + mWaveInfo.mOffsetStart; } JASSimpleWaveBank::TWaveHandle::TWaveHandle() { diff --git a/libs/JSystem/src/JAudio2/JASTaskThread.cpp b/libs/JSystem/src/JAudio2/JASTaskThread.cpp index 30a6d07a98..365424deb4 100644 --- a/libs/JSystem/src/JAudio2/JASTaskThread.cpp +++ b/libs/JSystem/src/JAudio2/JASTaskThread.cpp @@ -26,7 +26,7 @@ JASTaskThread::~JASTaskThread() { void* JASTaskThread::allocCallStack(JASThreadCallback callback, const void* msg, u32 msgSize) { ThreadMemPool* heap; - u32 size = msgSize + 8; + u32 size = msgSize + offsetof(JASThreadCallStack, msg); JASThreadCallStack *callStack = (JASThreadCallStack*) JASKernel::getCommandHeap()->alloc(size); if (callStack == NULL) { return NULL; @@ -40,7 +40,7 @@ void* JASTaskThread::allocCallStack(JASThreadCallback callback, const void* msg, void* JASTaskThread::allocCallStack(JASThreadCallback callback, void* msg) { JASThreadCallStack *callStack; - callStack = (JASThreadCallStack*)JASKernel::getCommandHeap()->alloc(12); + callStack = (JASThreadCallStack*)JASKernel::getCommandHeap()->alloc(offsetof(JASThreadCallStack, msg) + sizeof(void*)); if (callStack == NULL) { return NULL; } diff --git a/libs/JSystem/src/JAudio2/JASTrack.cpp b/libs/JSystem/src/JAudio2/JASTrack.cpp index de070adde3..68fbee63e5 100644 --- a/libs/JSystem/src/JAudio2/JASTrack.cpp +++ b/libs/JSystem/src/JAudio2/JASTrack.cpp @@ -171,9 +171,9 @@ void JASTrack::assignExtBuffer(u32 index, JASSoundParams* i_soundParams) { mChannelMgrs[index]->mSoundParams = i_soundParams; } -void JASTrack::setSeqData(void* param_0, u32 param_1) { +void JASTrack::setSeqData(void* base, u32 offset) { JUT_ASSERT(257, mStatus == STATUS_FREE); - mSeqCtrl.start(param_0, param_1); + mSeqCtrl.start(base, offset); } void JASTrack::startSeq() { @@ -356,7 +356,7 @@ int JASTrack::gateOn(u32 param_0, u32 i_velocity, f32 i_time, u32 i_flags) { } else { JASChannel* channel = channel_mgr->mChannels[0]; if (channel != NULL) { - channel->setKey(uvar7 - channel->field_0xdc.field_0x4.field_0x01); + channel->setKey(uvar7 - channel->field_0xdc.mWaveInfo.mBaseKey); channel->setVelocity(i_velocity); channel->setUpdateTimer(update_timer); } @@ -545,10 +545,10 @@ void JASTrack::setOscTable(u32 osc_no, JASOscillator::Point const* i_table) { void JASTrack::setOscAdsr(s16 param_0, s16 param_1, s16 param_2, s16 param_3, u16 i_directRelease) { mOscParam[0] = sEnvOsc; mOscParam[0].mTable = mOscPoint; - mOscPoint[0]._2 = param_0; - mOscPoint[1]._2 = param_1; - mOscPoint[2]._2 = param_2; - mOscPoint[2]._4 = param_3; + mOscPoint[0].mTime = param_0; + mOscPoint[1].mTime = param_1; + mOscPoint[2].mTime = param_2; + mOscPoint[2].mValue = param_3; mDirectRelease = i_directRelease; } diff --git a/libs/JSystem/src/JAudio2/JASTrackPort.cpp b/libs/JSystem/src/JAudio2/JASTrackPort.cpp index e822212ec9..bde86b37f9 100644 --- a/libs/JSystem/src/JAudio2/JASTrackPort.cpp +++ b/libs/JSystem/src/JAudio2/JASTrackPort.cpp @@ -3,8 +3,8 @@ #include "JSystem/JAudio2/JASTrackPort.h" void JASTrackPort::init() { - for (int i = 0; i < 16; i++) { - field_0x4[i] = 0; + for (int i = 0; i < MAX_PORTS; i++) { + mPortValues[i] = 0; } field_0x0 = 0; field_0x2 = 0; @@ -13,25 +13,25 @@ void JASTrackPort::init() { u16 JASTrackPort::readImport(u32 port_num) { JUT_ASSERT(27, port_num < MAX_PORTS); field_0x0 = field_0x0 & ~(1 << port_num); - return field_0x4[port_num]; + return mPortValues[port_num]; } u16 JASTrackPort::readExport(u32 port_num) { JUT_ASSERT(34, port_num < MAX_PORTS); field_0x2 = field_0x2 & ~(1 << port_num); - return field_0x4[port_num]; + return mPortValues[port_num]; } void JASTrackPort::writeImport(u32 port_num, u16 param_1) { JUT_ASSERT(41, port_num < MAX_PORTS); field_0x0 = field_0x0 | (1 << port_num); - field_0x4[port_num] = param_1; + mPortValues[port_num] = param_1; } void JASTrackPort::writeExport(u32 port_num, u16 param_1) { JUT_ASSERT(47, port_num < MAX_PORTS); field_0x2 = field_0x2 | (1 << port_num); - field_0x4[port_num] = param_1; + mPortValues[port_num] = param_1; } u32 JASTrackPort::checkImport(u32 param_0) const { diff --git a/libs/JSystem/src/JAudio2/JASWSParser.cpp b/libs/JSystem/src/JAudio2/JASWSParser.cpp index 35ec9526ed..4288377548 100644 --- a/libs/JSystem/src/JAudio2/JASWSParser.cpp +++ b/libs/JSystem/src/JAudio2/JASWSParser.cpp @@ -48,17 +48,17 @@ JASBasicWaveBank* JASWSParser::createBasicWaveBank(void const* stream, JKRHeap* for (int j = 0; j < ctrl->mWaveCount; j++) { TWave* wave = archive->mWaveOffsets[j].ptr(header); JASWaveInfo wave_info; - wave_info.field_0x00 = wave->_01; - wave_info.field_0x01 = wave->_02; - wave_info.field_0x04 = wave->_04; - wave_info.field_0x08 = wave->mOffset; - wave_info.field_0x0c = wave->_0C; - wave_info.field_0x02 = wave->_10 == 0 ? 0 : 0xff; - wave_info.field_0x10 = wave->_14; - wave_info.field_0x14 = wave->_18; - wave_info.field_0x18 = wave->_1C; - wave_info.field_0x1c = wave->_20; - wave_info.field_0x1e = wave->_22; + wave_info.mWaveFormat = wave->mWaveFormat; + wave_info.mBaseKey = wave->mBaseKey; + wave_info.mSampleRate = wave->mSampleRate; + wave_info.mOffsetStart = wave->mAWOffsetStart; + wave_info.mOffsetLength = wave->mAWOffsetEnd; + wave_info.mLoopFlag = wave->mLoopFlags == 0 ? 0 : 0xff; + wave_info.mLoopStartSample = wave->mLoopStartSample; + wave_info.mLoopEndSample = wave->mLoopEndSample; + wave_info.mSampleCount = wave->mSampleCount; + wave_info.mpLast = wave->mpLast; + wave_info.mpPenult = wave->mpPenult; TCtrlWave* ctrl_wave = ctrl->mCtrlWaveOffsets[j].ptr(header); u16 local_74 = JSULoHalf(ctrl_wave->_00); wave_bank->setWaveInfo(wave_group, j, local_74, wave_info); @@ -104,17 +104,17 @@ JASSimpleWaveBank* JASWSParser::createSimpleWaveBank(void const* stream, JKRHeap for (int i = 0; i < ctrl->mWaveCount; i++) { TWave* wave = archive->mWaveOffsets[i].ptr(header); JASWaveInfo wave_info; - wave_info.field_0x00 = wave->_01; - wave_info.field_0x01 = wave->_02; - wave_info.field_0x04 = wave->_04; - wave_info.field_0x08 = wave->mOffset; - wave_info.field_0x0c = wave->_0C; - wave_info.field_0x02 = wave->_10 == 0 ? 0 : 0xff; - wave_info.field_0x10 = wave->_14; - wave_info.field_0x14 = wave->_18; - wave_info.field_0x18 = wave->_1C; - wave_info.field_0x1c = wave->_20; - wave_info.field_0x1e = wave->_22; + wave_info.mWaveFormat = wave->mWaveFormat; + wave_info.mBaseKey = wave->mBaseKey; + wave_info.mSampleRate = wave->mSampleRate; + wave_info.mOffsetStart = wave->mAWOffsetStart; + wave_info.mOffsetLength = wave->mAWOffsetEnd; + wave_info.mLoopFlag = wave->mLoopFlags == 0 ? 0 : 0xff; + wave_info.mLoopStartSample = wave->mLoopStartSample; + wave_info.mLoopEndSample = wave->mLoopEndSample; + wave_info.mSampleCount = wave->mSampleCount; + wave_info.mpLast = wave->mpLast; + wave_info.mpPenult = wave->mpPenult; TCtrlWave* ctrl_wave = ctrl->mCtrlWaveOffsets[i].ptr(header); u32 tmp = JSULoHalf(ctrl_wave->_00); wave_bank->setWaveInfo(tmp, wave_info); diff --git a/libs/JSystem/src/JAudio2/JASWaveArcLoader.cpp b/libs/JSystem/src/JAudio2/JASWaveArcLoader.cpp index 54018a9e25..d14ff70298 100644 --- a/libs/JSystem/src/JAudio2/JASWaveArcLoader.cpp +++ b/libs/JSystem/src/JAudio2/JASWaveArcLoader.cpp @@ -99,7 +99,7 @@ bool JASWaveArc::sendLoadCmd() { _5a++; - if (JASDvd::getThreadPointer()->sendCmdMsg(loadToAramCallback, &commandInfo, 0x10) == 0) { + if (JASDvd::getThreadPointer()->sendCmdMsg(loadToAramCallback, &commandInfo, sizeof(commandInfo)) == 0) { JUT_WARN(193, "%s", "sendCmdMsg loadToAramCallback Failed"); mHeap.free(); return false; diff --git a/libs/JSystem/src/JAudio2/JAUInitializer.cpp b/libs/JSystem/src/JAudio2/JAUInitializer.cpp index 3800170f77..0cc3fcbb62 100644 --- a/libs/JSystem/src/JAudio2/JAUInitializer.cpp +++ b/libs/JSystem/src/JAudio2/JAUInitializer.cpp @@ -15,6 +15,8 @@ #include "JSystem/JKernel/JKRSolidHeap.h" #include "JSystem/JKernel/JKRThread.h" +#include "dusk/audio/DuskAudioSystem.h" + JAU_JASInitializer::JAU_JASInitializer() { audioMemory_ = 0; audioMemSize_ = 0; @@ -27,7 +29,7 @@ JAU_JASInitializer::JAU_JASInitializer() { #endif dvdThreadPriority_ = 3; audioThreadPriority_ = 2; - field_0x1c = 0x80; + mJasTrackPoolSize = 0x80; dspLevel_ = 1.0f; aramBlockSize_ = 0x2760; aramChannelNum_ = 2; @@ -54,13 +56,17 @@ void JAU_JASInitializer::initJASystem(JKRSolidHeap* heap) { JASKernel::setupAramHeap(audioMemory_, audioMemSize_); - JASTrack::newMemPool(field_0x1c); + JASTrack::newMemPool(mJasTrackPoolSize); if (field_0x20 > 0) { JASTrack::TChannelMgr::newMemPool(field_0x20); } JASDvd::createThread(dvdThreadPriority_, 0x80, 0x1000); +#if TARGET_PC + dusk::audio::Initialize(); +#else JASAudioThread::create(audioThreadPriority_); +#endif JKRThreadSwitch* threadSwitch = JKRThreadSwitch::getManager(); if (threadSwitch) { if (dvdThreadId_ >= 0) { @@ -80,33 +86,33 @@ void JAU_JASInitializer::initJASystem(JKRSolidHeap* heap) { } #if PLATFORM_SHIELD - JASDriver::setOutputMode(1); + JASDriver::setOutputMode(JAS_OUTPUT_STEREO); #else switch (OSGetSoundMode()) { - case 0: - JASDriver::setOutputMode(0); + case OS_SOUND_MODE_MONO: + JASDriver::setOutputMode(JAS_OUTPUT_MONO); break; - case 1: - JASDriver::setOutputMode(1); + case OS_SOUND_MODE_STEREO: + JASDriver::setOutputMode(JAS_OUTPUT_STEREO); break; } #endif } JAU_JAIInitializer::JAU_JAIInitializer() { - field_0x0 = 100; - field_0x4 = 4; - field_0x8 = 2; - field_0xc = 16; + mJaiSePoolSize = 100; + mJaiSeqPoolSize = 4; + mJaiStreamPoolSize = 2; + mJaiSoundChildPoolSize = 16; } // NONMATCHING JASPoolAllocObject<_> locations void JAU_JAIInitializer::initJAInterface() { s32 r30 = JASDram->getFreeSize(); - JAIStream::newMemPool(field_0x8); - JAISeq::newMemPool(field_0x4); - JAISe::newMemPool(field_0x0); - JAISoundChild::newMemPool(field_0xc); + JAIStream::newMemPool(mJaiStreamPoolSize); + JAISeq::newMemPool(mJaiSeqPoolSize); + JAISe::newMemPool(mJaiSePoolSize); + JAISoundChild::newMemPool(mJaiSoundChildPoolSize); s32 r29 = JASDram->getFreeSize(); OS_REPORT("JAU_JAIInitializer uses %d bytes\n", r30 - r29); } diff --git a/libs/JSystem/src/JAudio2/JAUSectionHeap.cpp b/libs/JSystem/src/JAudio2/JAUSectionHeap.cpp index 8207c21f2f..e1f45de1ae 100644 --- a/libs/JSystem/src/JAudio2/JAUSectionHeap.cpp +++ b/libs/JSystem/src/JAudio2/JAUSectionHeap.cpp @@ -245,11 +245,11 @@ u8* JAUSection::newStaticSeqDataBlock_(JAISoundID param_0, u32 size) { return NULL; } -bool JAUSection::newStaticSeqData(JAISoundID param_0, void const* param_1, u32 param_2) { +bool JAUSection::newStaticSeqData(JAISoundID param_0, void const* param_1, u32 size) { { - u8* r30 = newStaticSeqDataBlock_(param_0, param_2); + u8* r30 = newStaticSeqDataBlock_(param_0, size); if (r30) { - memcpy(r30, param_1, param_2); + memcpy(r30, param_1, size); return true; } } diff --git a/libs/JSystem/src/JAudio2/JAUSeqCollection.cpp b/libs/JSystem/src/JAudio2/JAUSeqCollection.cpp index 1301cbc4fd..a6071a75e6 100644 --- a/libs/JSystem/src/JAudio2/JAUSeqCollection.cpp +++ b/libs/JSystem/src/JAudio2/JAUSeqCollection.cpp @@ -4,39 +4,39 @@ #include "JSystem/JUtility/JUTAssert.h" JAUSeqCollection::JAUSeqCollection() { - field_0x8 = NULL; + mHeader = NULL; } void JAUSeqCollection::init(void const* param_0) { - field_0x8 = (const JAUSeqCollectionData*)param_0; - if (field_0x8->field_0x0 != 0x53 || field_0x8->field_0x1 != 0x43) { - field_0x8 = NULL; + mHeader = (const JAUSeqCollectionData*)param_0; + if (mHeader->mMagic1 != 0x53 || mHeader->mMagic2 != 0x43) { + mHeader = NULL; return; } - field_0x0 = field_0x8->field_0x2; - field_0xc = field_0x8->field_0x4; - field_0x4 = &field_0x8->field_0x8; + mNumSoundCategories = mHeader->mNumSoundCategories; + mSectionSize = mHeader->mSectionSize; + mTableOffsets = mHeader->mTableOffsets; } bool JAUSeqCollection::getSeqData(int param_0, int param_1, JAISeqData* param_2) { - if (param_0 >= field_0x0) { + if (param_0 >= mNumSoundCategories) { return false; } - u32 r29 = field_0x4[param_0]; - BE(u32)* puVar2 = (BE(u32)*)((u8*)field_0x8 + r29); + u32 r29 = mTableOffsets[param_0]; + BE(u32)* puVar2 = (BE(u32)*)((u8*)mHeader + r29); if (param_1 >= puVar2[0]) { return false; } - param_2->set((void*)field_0x8, puVar2[param_1 + 1]); + param_2->set((void*)mHeader, puVar2[param_1 + 1]); return true; } bool JAUSeqCollection::getSeqDataRegion(JAISeqDataRegion* param_0) { if (isValid()) { - param_0->addr = (u8*)field_0x8; - param_0->size = field_0xc; + param_0->addr = (u8*)mHeader; + param_0->size = mSectionSize; return true; } return false; diff --git a/libs/JSystem/src/JAudio2/JAUSeqDataBlockMgr.cpp b/libs/JSystem/src/JAudio2/JAUSeqDataBlockMgr.cpp index 2fafe9a4bc..698c4aff65 100644 --- a/libs/JSystem/src/JAudio2/JAUSeqDataBlockMgr.cpp +++ b/libs/JSystem/src/JAudio2/JAUSeqDataBlockMgr.cpp @@ -87,8 +87,8 @@ s32 JAUDynamicSeqDataBlocks::getSeqData(JAISoundID param_0, JAISeqDataUser* para u8* seqData = mLoadedBlocks.getSeqData(param_0); if (seqData != NULL) { - param_2->field_0x0 = seqData; - param_2->field_0x4 = 0; + param_2->mBase = seqData; + param_2->mOffset = 0; return 2; } diff --git a/libs/JSystem/src/JAudio2/dspproc.cpp b/libs/JSystem/src/JAudio2/dspproc.cpp index a9c08e37ff..891722b7f4 100644 --- a/libs/JSystem/src/JAudio2/dspproc.cpp +++ b/libs/JSystem/src/JAudio2/dspproc.cpp @@ -20,10 +20,14 @@ static void setup_callback(u16 param_0) { flag = FALSE; } -void DsetupTable(u32 param_0, u32 param_1, u32 param_2, u32 param_3, u32 param_4) { +void DsetupTable(u32 channelCount, u32 channelBufferAddress, u32 param_2, u32 param_3, u32 param_4) { +#if TARGET_PC + return; +#endif + u32 table[5]; - table[0] = (param_0 & 0xFFFF) | 0x81000000; - table[1] = param_1; + table[0] = (channelCount & 0xFFFF) | 0x81000000; + table[1] = channelBufferAddress; table[2] = param_2; table[3] = param_3; table[4] = param_4; diff --git a/libs/JSystem/src/JAudio2/dsptask.cpp b/libs/JSystem/src/JAudio2/dsptask.cpp index 86d6323333..7d2e8dd2ad 100644 --- a/libs/JSystem/src/JAudio2/dsptask.cpp +++ b/libs/JSystem/src/JAudio2/dsptask.cpp @@ -4,6 +4,7 @@ #include "JSystem/JAudio2/osdsp.h" #include "global.h" #include "os_report.h" +#include "dusk/logging.h" static void DspInitWork(); static void DspHandShake(void* param_0); @@ -527,7 +528,7 @@ static DSPTaskInfo audio_task ATTRIBUTE_ALIGN(32); static u8 AUDIO_YIELD_BUFFER[8192] ATTRIBUTE_ALIGN(32); -void DspBoot(void (*param_0)(void*)) { +void DspBoot(void (*requestCallback)(void*)) { DspInitWork(); OS_REPORT("Dsp をブートします\n"); audio_task.priority = 0xf0; @@ -542,13 +543,16 @@ void DspBoot(void (*param_0)(void*)) { audio_task.init_cb = DspHandShake; audio_task.res_cb = NULL; audio_task.done_cb = NULL; - audio_task.req_cb = param_0; + audio_task.req_cb = requestCallback; DSPInit(); DSPAddPriorTask(&audio_task); OS_REPORT("Dspブートしました\n"); } int DSPSendCommands2(u32* param_1, u32 param_2, void (*callBack)(u16)) { +#if TARGET_PC + OSPanic(__FILE__, __LINE__, "We do not have a DSP"); +#endif s32 i; BOOL interruptFlag; s32 startWorkStatus; diff --git a/libs/JSystem/src/JAudio2/osdsp_task.cpp b/libs/JSystem/src/JAudio2/osdsp_task.cpp index d9f4973880..7ec8f3f855 100644 --- a/libs/JSystem/src/JAudio2/osdsp_task.cpp +++ b/libs/JSystem/src/JAudio2/osdsp_task.cpp @@ -12,7 +12,7 @@ extern "C" void __DSP_remove_task(DSPTaskInfo* task); static void Dsp_Update_Request(); -static vu8 struct_80451308; +static vu8 DspRunningStatus; static u8 struct_80451309; DSPTaskInfo* DSP_prior_task; @@ -23,7 +23,7 @@ extern "C" void __DSPHandler(__OSInterrupt interrupt, OSContext* context) { OSClearContext(&funcContext); OSSetCurrentContext(&funcContext); - if (struct_80451308 == 1 || struct_80451308 == 0) { + if (DspRunningStatus == 1 || DspRunningStatus == 0) { __DSP_curr_task = DSP_prior_task; } @@ -38,7 +38,7 @@ extern "C" void __DSPHandler(__OSInterrupt interrupt, OSContext* context) { case 0xDCD10000: __DSP_curr_task->state = 1; if (__DSP_curr_task == DSP_prior_task) { - struct_80451308 = 1; + DspRunningStatus = 1; } if (__DSP_curr_task->init_cb != NULL) { __DSP_curr_task->init_cb(__DSP_curr_task); @@ -47,7 +47,7 @@ extern "C" void __DSPHandler(__OSInterrupt interrupt, OSContext* context) { case 0xDCD10001: __DSP_curr_task->state = 1; if (__DSP_curr_task == DSP_prior_task) { - struct_80451308 = 1; + DspRunningStatus = 1; Dsp_Update_Request(); } if (__DSP_curr_task->res_cb != NULL) { @@ -97,7 +97,7 @@ extern "C" void __DSPHandler(__OSInterrupt interrupt, OSContext* context) { __DSP_curr_task = DSP_prior_task; Dsp_Update_Request(); } else { - struct_80451308 = 3; + DspRunningStatus = 3; DSPSendMailToDSP(0xCDD10001); while (DSPCheckMailToDSP() != 0); __DSP_exec_task(DSP_prior_task, __DSP_first_task); @@ -113,7 +113,7 @@ extern "C" void __DSPHandler(__OSInterrupt interrupt, OSContext* context) { static u32 sync_stack[5]; void DsyncFrame2(u32 param_0, u32 param_1, u32 param_2) { - if (struct_80451308 != 1) { + if (DspRunningStatus != 1) { sync_stack[0] = param_0; struct_80451309 = 1; sync_stack[1] = param_1; @@ -125,7 +125,7 @@ void DsyncFrame2(u32 param_0, u32 param_1, u32 param_2) { } static void DsyncFrame3(u32 param_0, u32 param_1, u32 param_2, u32 param_3, u32 param_4) { - if (struct_80451308 != 1) { + if (DspRunningStatus != 1) { sync_stack[0] = param_0; struct_80451309 = 2; sync_stack[1] = param_1; @@ -152,9 +152,9 @@ static void Dsp_Update_Request() { } int Dsp_Running_Check() { - return struct_80451308 == 1 ? TRUE : FALSE; + return DspRunningStatus == 1 ? TRUE : FALSE; } void Dsp_Running_Start() { - struct_80451308 = 1; + DspRunningStatus = 1; } diff --git a/libs/JSystem/src/JKernel/JKRAramPiece.cpp b/libs/JSystem/src/JKernel/JKRAramPiece.cpp index f01b530cfe..0946275b83 100644 --- a/libs/JSystem/src/JKernel/JKRAramPiece.cpp +++ b/libs/JSystem/src/JKernel/JKRAramPiece.cpp @@ -27,6 +27,10 @@ JSUList JKRAramPiece::sAramPieceCommandList; OSMutex JKRAramPiece::mMutex; +#if DEBUG && TARGET_PC +volatile u8 forceRead; +#endif + JKRAMCommand* JKRAramPiece::orderAsync(int direction, uintptr_t source, uintptr_t destination, u32 length, JKRAramBlock* block, JKRAMCommand::AsyncCallback callback) { lock(); @@ -45,6 +49,12 @@ JKRAMCommand* JKRAramPiece::orderAsync(int direction, uintptr_t source, uintptr_ JKRAramPiece::prepareCommand(direction, source, destination, length, block, callback); message->setting(1, command); +#if DEBUG && TARGET_PC + if (direction == ARAM_DIR_MRAM_TO_ARAM) { + forceRead = *reinterpret_cast(source); + } +#endif + OSSendMessage(&JKRAram::sMessageQueue, message, OS_MESSAGE_BLOCK); if (command->mCallback != NULL) { sAramPieceCommandList.append(&command->mPieceLink); diff --git a/libs/JSystem/src/JKernel/JKRHeap.cpp b/libs/JSystem/src/JKernel/JKRHeap.cpp index bc02d877fb..ce1899a4ba 100644 --- a/libs/JSystem/src/JKernel/JKRHeap.cpp +++ b/libs/JSystem/src/JKernel/JKRHeap.cpp @@ -15,6 +15,7 @@ #include "JSystem/JUtility/JUTAssert.h" #include "JSystem/JUtility/JUTException.h" +#include "dusk/string.hpp" #ifdef __MWERKS__ #include #else @@ -585,7 +586,13 @@ void* operator new(size_t size JKR_HEAP_TOKEN_PARAM, int alignment) { #endif void* operator new(size_t size JKR_HEAP_TOKEN_PARAM, JKRHeap* heap, int alignment) { - return JKRHeap::alloc(size, alignment, heap); + void* mem = JKRHeap::alloc(size, alignment, heap); +#if TARGET_PC + if (mem == nullptr) { + return fallback_alloc(size, abs(alignment), true); + } +#endif + return mem; } #if !TARGET_PC @@ -695,9 +702,7 @@ JKRHeap* JKRHeap::getCurrentHeap() { } void JKRHeap::setName(const char* name) { - size_t len = strlen(name); - strncpy(mName, name, sizeof(mName) - 1); - mName[sizeof(mName) - 1] = '\0'; + dusk::SafeStringCopyTruncate(mName, name); } void JKRHeap::setNamef(const char* fmt, ...) { diff --git a/libs/JSystem/src/JKernel/JKRThread.cpp b/libs/JSystem/src/JKernel/JKRThread.cpp index 96dfd53499..6ba97e3d4a 100644 --- a/libs/JSystem/src/JKernel/JKRThread.cpp +++ b/libs/JSystem/src/JKernel/JKRThread.cpp @@ -7,6 +7,10 @@ #include "global.h" #include +#if TARGET_PC +#include "dusk/os.h" +#endif + JSUList JKRThread::sThreadList(0); void* JKRIdleThread::sThread; @@ -88,6 +92,14 @@ void JKRThread::setCommon_heapSpecified(JKRHeap* heap, u32 stack_size, int param } void* JKRThread::start(void* thread) { +#if TARGET_PC + auto& thd = *static_cast(thread); + if (thd.mThreadName == nullptr) { + thd.mThreadName = typeid(thd).name(); + } + OSSetCurrentThreadName(thd.mThreadName); +#endif + return ((JKRThread*)thread)->run(); } diff --git a/src/Z2AudioLib/Z2Audience.cpp b/src/Z2AudioLib/Z2Audience.cpp index be7bd4b126..9adab4084f 100644 --- a/src/Z2AudioLib/Z2Audience.cpp +++ b/src/Z2AudioLib/Z2Audience.cpp @@ -552,7 +552,11 @@ JAIAudible* Z2Audience::newAudible(const JGeometry::TVec3& pos, JAISoundID } void Z2Audience::deleteAudible(JAIAudible* audible) { +#if TARGET_PC + JKR_DELETE(static_cast(audible)); +#else JKR_DELETE(audible); +#endif } Z2Audible::~Z2Audible() {} diff --git a/src/Z2AudioLib/Z2AudioMgr.cpp b/src/Z2AudioLib/Z2AudioMgr.cpp index 3ef726dda7..985c500aec 100644 --- a/src/Z2AudioLib/Z2AudioMgr.cpp +++ b/src/Z2AudioLib/Z2AudioMgr.cpp @@ -31,15 +31,15 @@ Z2AudioMgr::Z2AudioMgr() : mSoundStarter(true) { void Z2AudioMgr::init(JKRSolidHeap* heap, u32 memSize, void* baaData, JKRArchive* seqArc) { JAU_JASInitializer JASInitializer; JASInitializer.audioMemSize_ = memSize; - JASInitializer.field_0x1c = 140; + JASInitializer.mJasTrackPoolSize = 140; JASInitializer.dspLevel_ = 1.3f; JASInitializer.waveArcDir_ = "Audiores/Waves/"; JASInitializer.initJASystem(heap); JAU_JAIInitializer JAIInitializer; - JAIInitializer.field_0x0 = 78; - JAIInitializer.field_0x4 = 4; - JAIInitializer.field_0xc = 48; + JAIInitializer.mJaiSePoolSize = 78; + JAIInitializer.mJaiSeqPoolSize = 4; + JAIInitializer.mJaiSoundChildPoolSize = 48; JAIInitializer.initJAInterface(); JAISeMgr* seMgr = mSoundMgr.getSeMgr(); @@ -107,19 +107,6 @@ void Z2AudioMgr::init(JKRSolidHeap* heap, u32 memSize, void* baaData, JKRArchive JASPoolAllocObject::newMemPool(0x4e); OS_REPORT("[Z2AudioMgr::init]before Create Section: %d\n", heap->getFreeSize()); -#if TARGET_PC - // Fix a race condition with OS threading where JAUNewSectionHeap will use all the remaining - // space in the JASDram heap before JASAudioThread has finished initializing. - - OSLockMutex(&JASAudioThread::sThreadInitCompleteMutex); - while (!JASAudioThread::sThreadInitComplete) { - OSWaitCond( - &JASAudioThread::sThreadInitCompleteCond, - &JASAudioThread::sThreadInitCompleteMutex); - } - OSUnlockMutex(&JASAudioThread::sThreadInitCompleteMutex); -#endif - JAUSectionHeap* sectionHeap = JAUNewSectionHeap(true); sectionHeap->setSeqDataArchive(seqArc); size_t resMaxSize = JASResArcLoader::getResMaxSize(seqArc); @@ -158,7 +145,7 @@ void Z2AudioMgr::init(JKRSolidHeap* heap, u32 memSize, void* baaData, JKRArchive } void Z2AudioMgr::setOutputMode(u32 mode) { - if (mode <= 2) { + if (mode <= JAS_OUTPUT_SURROUND) { JAISetOutputMode(mode); } } diff --git a/src/Z2AudioLib/Z2Creature.cpp b/src/Z2AudioLib/Z2Creature.cpp index a17e3d516c..7a27e9e9c4 100644 --- a/src/Z2AudioLib/Z2Creature.cpp +++ b/src/Z2AudioLib/Z2Creature.cpp @@ -211,11 +211,6 @@ Z2SoundHandlePool* Z2Creature::startCreatureSoundLevel(JAISoundID soundID, u32 m } Z2SoundHandlePool* Z2Creature::startCreatureVoice(JAISoundID soundID, s8 reverb) { - #if TARGET_PC - // stubbed - return nullptr; - #endif - switch (soundID) { case Z2SE_MDN_V_FLY_OUT: case Z2SE_MDN_V_MGN_TAME: diff --git a/src/Z2AudioLib/Z2SceneMgr.cpp b/src/Z2AudioLib/Z2SceneMgr.cpp index a31cd534ca..1b2152fcb7 100644 --- a/src/Z2AudioLib/Z2SceneMgr.cpp +++ b/src/Z2AudioLib/Z2SceneMgr.cpp @@ -2018,10 +2018,6 @@ bool Z2SceneMgr::loadSceneWave(u32 wave, u32 bank) { #endif bool Z2SceneMgr::loadSeWave(u32 wave) { - return 0; -} - -/* //lw stub lw JAUSectionHeap* sectionHeap = JASGlobalInstance::getInstance(); JUT_ASSERT(3030, sectionHeap); @@ -2036,13 +2032,8 @@ bool Z2SceneMgr::loadSeWave(u32 wave) { JUT_WARN_DEVICE(3038, 1, "Z2SceneMgr::cannot load SE wave:%d\n", wave); return false; } -*/ + bool Z2SceneMgr::loadBgmWave(u32 wave) { - return true; -} - - /* //lw stub lw - JAUSectionHeap* sectionHeap = JASGlobalInstance::getInstance(); JUT_ASSERT(3047, sectionHeap); @@ -2056,4 +2047,4 @@ bool Z2SceneMgr::loadBgmWave(u32 wave) { JUT_WARN_DEVICE(3055, 1, "Z2SceneMgr::cannot load BGM wave:%d\n", wave); return false; -} */ +} diff --git a/src/Z2AudioLib/Z2SoundHandles.cpp b/src/Z2AudioLib/Z2SoundHandles.cpp index 9b6aa5a9ba..de7e265ae7 100644 --- a/src/Z2AudioLib/Z2SoundHandles.cpp +++ b/src/Z2AudioLib/Z2SoundHandles.cpp @@ -40,7 +40,7 @@ Z2SoundHandlePool* Z2SoundHandles::getHandleSoundID(JAISoundID soundID) { return NULL; } -Z2SoundHandlePool* Z2SoundHandles::getHandleUserData(u32 userData) { +Z2SoundHandlePool* Z2SoundHandles::getHandleUserData(uintptr_t userData) { JSULink* i; for (i = getFirst(); i != NULL; i = i->getNext()) { Z2SoundHandlePool* handle = i->getObject(); diff --git a/src/Z2AudioLib/Z2SoundObject.cpp b/src/Z2AudioLib/Z2SoundObject.cpp index 93d40c95cf..1c81be0f17 100644 --- a/src/Z2AudioLib/Z2SoundObject.cpp +++ b/src/Z2AudioLib/Z2SoundObject.cpp @@ -502,7 +502,7 @@ void Z2SoundObjAnime::startSoundInner(const JGeometry::TVec3& pos, f32 para JUT_ASSERT(747, curSoundIndex_ < animation_->getNumSounds()); const JAUSoundAnimationSound* animationSound = animation_->getSound(curSoundIndex_); - u32 user_data = (uintptr_t)animationSound; + uintptr_t user_data = (uintptr_t)animationSound; if (reverse_) { curSoundIndex_--; } else { diff --git a/src/d/actor/d_a_alink.cpp b/src/d/actor/d_a_alink.cpp index 58e8935e7d..4f106ece22 100644 --- a/src/d/actor/d_a_alink.cpp +++ b/src/d/actor/d_a_alink.cpp @@ -1467,7 +1467,7 @@ static f32 l_ladderAnmBaseTransY = 102.00054168701172f; static dCcD_SrcCyl l_cylSrc = { { - {0, {{AT_TYPE_WOLF_ATTACK, 3, 0x1A}, {0xD8FFFDFF, 5}, 0x73}}, + {0, {{(u32)AT_TYPE_WOLF_ATTACK, 3, 0x1A}, {0xD8FFFDFF, 5}, 0x73}}, {dCcD_SE_WOLF_BITE, 3, 1, 0, {1}}, {dCcD_SE_NONE, 6, 0, 0, {0}}, {0}, diff --git a/src/d/actor/d_a_movie_player.cpp b/src/d/actor/d_a_movie_player.cpp index c2d1c394c0..0f9f68fb50 100644 --- a/src/d/actor/d_a_movie_player.cpp +++ b/src/d/actor/d_a_movie_player.cpp @@ -3268,7 +3268,7 @@ static void daMP_MixAudio(s16* destination, s16*, u32 sample) { if (r_mix > 32767) r_mix = 32767; - if (JASDriver::getOutputMode() == 0) { + if (JASDriver::getOutputMode() == JAS_OUTPUT_MONO) { l_mix = r_mix = ((r_mix >> 1) + (l_mix >> 1)); r_mix = (s16)r_mix; l_mix = (s16)l_mix; diff --git a/src/d/d_menu_option.cpp b/src/d/d_menu_option.cpp index 5e00afe208..abe9f864ce 100644 --- a/src/d/d_menu_option.cpp +++ b/src/d/d_menu_option.cpp @@ -24,6 +24,8 @@ #include "m_Do/m_Do_graphic.h" #include +#include "JSystem/JAudio2/JASDriverIF.h" + typedef void (dMenu_Option_c::*initFunc)(); static initFunc init[] = { &dMenu_Option_c::atten_init, @@ -89,7 +91,7 @@ dMenu_Option_c::dMenu_Option_c(JKRArchive* i_archive, STControl* i_stick) { dMenu_Option_c::~dMenu_Option_c() {} -static const u32 dMo_soundMode[3] = {0, 1, 2}; +static const u32 dMo_soundMode[3] = {JAS_OUTPUT_MONO, JAS_OUTPUT_STEREO, JAS_OUTPUT_SURROUND}; void dMenu_Option_c::_create() { static const u64 text_a_tag[5] = {MULTI_CHAR('atext1_1'), MULTI_CHAR('atext1_2'), MULTI_CHAR('atext1_3'), MULTI_CHAR('atext1_4'), MULTI_CHAR('atext1_5')}; @@ -1755,13 +1757,13 @@ void dMenu_Option_c::screenSet() { } } -void dMenu_Option_c::setSoundMode(u32 param_0) { - switch (param_0) { - case 0: +void dMenu_Option_c::setSoundMode(u32 soundMode) { + switch (soundMode) { + case JAS_OUTPUT_MONO: OSSetSoundMode(OS_SOUND_MODE_MONO); break; - case 1: - case 2: + case JAS_OUTPUT_STEREO: + case JAS_OUTPUT_SURROUND: // Via dolby pro logic 2, so it's over 2 output channels. OSSetSoundMode(OS_SOUND_MODE_STEREO); break; } diff --git a/src/d/d_msg_object.cpp b/src/d/d_msg_object.cpp index da9605c4b2..9a8f6d594a 100644 --- a/src/d/d_msg_object.cpp +++ b/src/d/d_msg_object.cpp @@ -1634,7 +1634,12 @@ void dMsgObject_c::readMessageGroupLocal(mDoDvdThd_mountXArchive_c** p_arcMount) #elif REGION_JPN sprintf(arcName, "/res/Msgjp/bmgres%d.arc", msgGroup); #else +#if TARGET_PC + // Original game UB + snprintf(arcName, sizeof(arcName), "/res/Msgus/bmgres%d.arc", msgGroup); +#else sprintf(arcName, "/res/Msgus/bmgres%d.arc", msgGroup); +#endif #endif *p_arcMount = mDoDvdThd_mountXArchive_c::create(arcName, 0, JKRArchive::MOUNT_MEM, NULL); diff --git a/src/d/d_stage.cpp b/src/d/d_stage.cpp index f6c90b0f3d..53f610267f 100644 --- a/src/d/d_stage.cpp +++ b/src/d/d_stage.cpp @@ -21,6 +21,8 @@ #include "m_Do/m_Do_Reset.h" #include #include + +#include "dusk/string.hpp" #if TARGET_PC #include #include @@ -151,7 +153,14 @@ static int dStage_RoomKeepDoorInit(dStage_dt_c* i_stage, void* i_data, int entry } void dStage_startStage_c::set(const char* i_Name, s8 i_RoomNo, s16 i_Point, s8 i_Layer) { +#if TARGET_PC + // UB fix. + if (mName != i_Name) { + dusk::SafeStringCopy(mName, i_Name); + } +#else strcpy(mName, i_Name); +#endif mRoomNo = i_RoomNo; mPoint = i_Point; mLayer = i_Layer; diff --git a/src/dusk/OSThread.cpp b/src/dusk/OSThread.cpp index c88126bd52..7daa2cb137 100644 --- a/src/dusk/OSThread.cpp +++ b/src/dusk/OSThread.cpp @@ -17,6 +17,12 @@ #include #include "JSystem/JKernel/JKRHeap.h" +#include "dusk/os.h" + +#if _WIN32 +#define WIN32_LEAN_AND_MEAN 1 +#include +#endif // ============================================================================ // Side-table: native thread data per OSThread @@ -695,6 +701,30 @@ OSInterruptMask __OSUnmaskInterrupts(OSInterruptMask mask) { return 0; } +void OSSetCurrentThreadName(const char* name) { + // "Why is this current thread only?", you might ask? + // Because macOS requires that. For some reason. + +#if _WIN32 + wchar_t buffer[256]; + const auto converted = MultiByteToWideChar( + CP_UTF8, + 0, + name, + -1, + buffer, + sizeof(buffer)/sizeof(wchar_t)); + if (converted == 0) { + CRASH("OSSetThreadName: MultiByteToWideChar failed"); + } + + const auto result = SetThreadDescription(GetCurrentThread(), buffer); + if (!SUCCEEDED(result)) { + CRASH("OSSetThreadName: SetThreadDescription failed"); + } +#endif +} + #ifdef __cplusplus } #endif diff --git a/src/dusk/audio/Adpcm.cpp b/src/dusk/audio/Adpcm.cpp new file mode 100644 index 0000000000..67b9ac9fd3 --- /dev/null +++ b/src/dusk/audio/Adpcm.cpp @@ -0,0 +1,61 @@ +#include "Adpcm.hpp" + +#include +#include + +#include "JSystem/JAudio2/JASAramStream.h" + +// https://github.com/magcius/vgmtrans/blob/8e34ddc2fb43948dc1e1a8759c739a0c1c7b62d7/src/main/formats/JaiSeqScanner.cpp#L489-L531 +// https://github.com/XAYRGA/JaiSeqX/blob/f29c024ec3663503f506aa02bcd503ada6e7d8aa/JaiSeqXLJA/DSP/JAIDSPADPCM4.cs#L86-L87 + +static constexpr u16 Coefficient0[] = { + 0,0x0800,0,0x0400, + 0x1000,0x0e00,0x0c00,0x1200, + 0x1068,0x12c0,0x1400,0x0800, + 0x0400,0xfc00,0xfc00,0xf800 +}; + +static constexpr u16 Coefficient1[] = { + 0,0,0x0800,0x0400,0xf800, + 0xfa00,0xfc00,0xf600,0xf738, + 0xf704,0xf400,0xf800,0xfc00, + 0x0400,0,0, +}; + +constexpr int AdpcmFrameSize = 9; + +static s16 Clamp16(s32 value) { + if (value > 0x7FFF) return 0x7FFF; + if (value < -0x8000) return -0x8000; + return value; +} + +void dusk::audio::Adpcm4ToPcm16(const u8* adpcm, size_t adpcmLength, s16* pcm, size_t pcmLength, s16& hist2, s16& hist1) { + assert (adpcmLength % AdpcmFrameSize == 0 && "ADPCM must be divisible by frame size"); + + auto endPtr = pcm + pcmLength; + + for (int i = 0; i < adpcmLength; i += AdpcmFrameSize) { + u8 header = adpcm[i]; + + s32 scale = 1 << (header >> 4); + u8 coefIndex = header & 0xF; + + s16 coef0 = (s16)Coefficient0[coefIndex]; + s16 coef1 = (s16)Coefficient1[coefIndex]; + + for (int sampleIdx = 0; sampleIdx < 16; sampleIdx++) { + u8 adpcmValue = adpcm[i + 1 + sampleIdx / 2]; + u8 unsignedNibble = sampleIdx % 2 == 0 ? adpcmValue >> 4 : adpcmValue & 0xF; + s8 signedNibble = ((s8)(unsignedNibble << 4)) >> 4; + s16 sample = Clamp16((((signedNibble * scale) << 11) + (coef0 * hist1 + coef1 * hist2)) >> 11); + + hist2 = hist1; + hist1 = sample; + + *pcm++ = sample; + if (endPtr == pcm) + return; + } + } +} diff --git a/src/dusk/audio/Adpcm.hpp b/src/dusk/audio/Adpcm.hpp new file mode 100644 index 0000000000..e893d54791 --- /dev/null +++ b/src/dusk/audio/Adpcm.hpp @@ -0,0 +1,14 @@ +#ifndef DUSK_ADPCM_HPP +#define DUSK_ADPCM_HPP + +#include + +namespace dusk::audio { + constexpr u32 Adpcm4FrameSize = 9; + constexpr u32 AdpcmSampleCount = 16; + constexpr u32 Adpcm2FrameSize = 5; + + void Adpcm4ToPcm16(const u8* adpcm, size_t adpcmLength, s16* pcm, size_t pcmLength, s16& hist1, s16& hist0); +} + +#endif // DUSK_ADPCM_HPP diff --git a/src/dusk/audio/DspStub.cpp b/src/dusk/audio/DspStub.cpp new file mode 100644 index 0000000000..c2dec809f2 --- /dev/null +++ b/src/dusk/audio/DspStub.cpp @@ -0,0 +1,35 @@ +#include "JSystem/JAudio2/dspproc.h" +#include "JSystem/JAudio2/osdsp_task.h" +#include "JSystem/JAudio2/dsptask.h" +#include "global.h" +#include "os.h" + +void DSPReleaseHalt2(u32) { + CRASH("We do not directly emulate the DSP"); +} +void DsetupTable(u32, u32, u32, u32, u32) { + // Nada. +} +void DsetMixerLevel(f32) { + // Nada for now, but maybe we should care about this? +} +void DsyncFrame2ch(u32, u32, u32) { + CRASH("We do not directly emulate the DSP"); +} +void DsyncFrame4ch(u32, u32, u32, u32, u32) { + CRASH("We do not directly emulate the DSP"); +} + +void DspBoot(void (*)(void*)) { + CRASH("We do not directly emulate the DSP"); +} +void DspFinishWork(u16) { + CRASH("We do not directly emulate the DSP"); +} +int DSPSendCommands2(u32*, u32, void (*)(u16)) { + CRASH("We do not directly emulate the DSP"); +} + +void DsyncFrame2(u32, u32, u32) { + CRASH("We do not directly emulate the DSP"); +} diff --git a/src/dusk/audio/DuskAudioSystem.cpp b/src/dusk/audio/DuskAudioSystem.cpp new file mode 100644 index 0000000000..0ed2101dcf --- /dev/null +++ b/src/dusk/audio/DuskAudioSystem.cpp @@ -0,0 +1,149 @@ +#include "dusk/audio/DuskAudioSystem.h" + +#include +#include +#include +#include +#include +#include + +#include "JSystem/JAudio2/JASAiCtrl.h" +#include "JSystem/JAudio2/JASChannel.h" +#include "JSystem/JAudio2/JASCriticalSection.h" +#include "JSystem/JAudio2/JASDSPChannel.h" +#include "JSystem/JAudio2/JASHeapCtrl.h" + +#include "DuskDsp.hpp" +#include "JSystem/JAudio2/JASAudioThread.h" +#include "JSystem/JAudio2/JASDriverIF.h" + +// #define DUSK_DUMP_AUDIO + +using namespace dusk::audio; + +static OutputSubframe OutBuffer; +static std::array OutInterleaveBuffer; + +static SDL_AudioStream* PlaybackStream; + +/** + * SDL audiostream callback to trigger rendering of new audio data. + */ +static void SDLCALL GetNewAudio( + void*, + SDL_AudioStream*, + int needed, + int); + +/** + * Render an entire new frame of audio and output it to SDL3. + * Note: "audio frames" are unrelated to video frames. + * @return Amount of audio samples rendered. + */ +static int RenderNewAudioFrame(); + +/** + * Render an audio subframe and output it to SDL3. + */ +static void RenderAudioSubframe(); + +static void InitSDL3Output() { + SDL_Init(SDL_INIT_AUDIO); + + constexpr SDL_AudioSpec spec = { + SDL_AUDIO_F32, + 2, + SampleRate, + }; + PlaybackStream = SDL_OpenAudioDeviceStream( + SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, + &spec, + &GetNewAudio, + nullptr); +} + +void dusk::audio::Initialize() { + InitSDL3Output(); + DspInit(); + + JASDsp::initBuffer(); + JASDSPChannel::initAll(); + + JASPoolAllocObject_MultiThreaded::newMemPool(0x48); + + SDL_ResumeAudioStreamDevice(PlaybackStream); +} + +void dusk::audio::SetMasterVolume(const f32 value) { + JASCriticalSection section; + + MasterVolume = value; +} + +void SDLCALL GetNewAudio( + void*, + SDL_AudioStream*, + int needed, + int) { + while (needed > 0) { + const int rendered = RenderNewAudioFrame(); + needed -= rendered; + } +} + +#if defined(DUSK_DUMP_AUDIO) +static std::ofstream outRaw("guh.raw", std::ios_base::out | std::ios_base::binary); +#endif + +int RenderNewAudioFrame() { + JASCriticalSection section; + const u32 countSubframes = JASDriver::getSubFrames(); + + JASAudioThread::setDSPSyncCount(countSubframes); + + for (u32 i = 0; i < countSubframes; i++) { + RenderAudioSubframe(); + + JASAudioThread::snIntCount -= 1; + } + +#if defined(DUSK_DUMP_AUDIO) + outRaw.flush(); +#endif + + return static_cast(countSubframes) * DSP_SUBFRAME_SIZE; +} + +static void InterleaveOutputData(const OutputSubframe& data, std::span target) { + assert(target.size() >= data.channels[0].size() * OutputSubframe::NUM_CHANNELS); + + size_t outPos = 0; + for (size_t inPos = 0; inPos < data.channels[0].size(); inPos++) { + for (size_t channelIdx = 0; channelIdx < OutputSubframe::NUM_CHANNELS; channelIdx++) { + target[outPos++] = data.channels[channelIdx][inPos]; + } + } +} + +void RenderAudioSubframe() { + OutBuffer = {}; + + JASDriver::updateDSP(); + DspRender(OutBuffer); + + InterleaveOutputData(OutBuffer, OutInterleaveBuffer); + +#if defined(DUSK_DUMP_AUDIO) + outRaw.write((const char*)OutInterleaveBuffer.data(), sizeof(OutInterleaveBuffer)); +#endif + + SDL_PutAudioStreamData(PlaybackStream, &OutInterleaveBuffer, sizeof(OutInterleaveBuffer)); +} + +u32 dusk::audio::GetResetCount(int channelIdx) { + return ChannelAux[channelIdx].resetCount; +} + +f32 dusk::audio::VolumeFromU16(u16 value) { + return static_cast(value) / static_cast(JASDriver::getChannelLevel_dsp()); +} diff --git a/src/dusk/audio/DuskDsp.cpp b/src/dusk/audio/DuskDsp.cpp new file mode 100644 index 0000000000..2b26ea478c --- /dev/null +++ b/src/dusk/audio/DuskDsp.cpp @@ -0,0 +1,497 @@ +#include +#include + +#include "DuskDsp.hpp" + +#include +#include +#include + +#include "Adpcm.hpp" +#include "JSystem/JAudio2/JASDriverIF.h" +#include "dusk/audio/DuskAudioSystem.h" +#include "dusk/endian.h" +#include "global.h" + +using namespace dusk::audio; + +ChannelAuxData dusk::audio::ChannelAux[DSP_CHANNELS] = {}; + +f32 dusk::audio::MasterVolume = 1.0f; +f32 dusk::audio::PrevMasterVolume = 1.0f; + +/** + * Validate that a DSP channel's format is actually something we know how to play. + */ +static bool ValidateChannelWaveFormat(const JASDsp::TChannel& channel) { + if (channel.mSamplesPerBlock == AdpcmSampleCount && channel.mBytesPerBlock == Adpcm4FrameSize) + return true; + if (channel.mSamplesPerBlock == 1 && channel.mBytesPerBlock == 16) + return true; + /* + if (channel.mSamplesPerBlock == AdpcmSampleCount && channel.mBytesPerBlock == Adpcm2FrameSize) + return true; + if (channel.mSamplesPerBlock == 1 && channel.mBytesPerBlock == 8) + return true; + */ + return false; +} + +/** + * Validate that a DSP channel is actually something we know how to play. + */ +static void ValidateChannel(const JASDsp::TChannel& channel) { + if (!ValidateChannelWaveFormat(channel)) { + CRASH( + "Unable to handle channel format: %02x, %02x\n", + channel.mSamplesPerBlock, + channel.mBytesPerBlock); + } +} + +static u32 ConvertSamplesToDataLength(const JASDsp::TChannel& channel, u32 samples) { + if (samples % channel.mSamplesPerBlock != 0) { + // Ensure we round up. + samples += channel.mSamplesPerBlock; + //CRASH("Indivisible sample count: %d\n", samples); + } + + return (samples / channel.mSamplesPerBlock) * BlockBytes(channel); +} + +/** + * Render the audio data contributed by a single DSP channel. Reads & decodes new input samples. + */ +static void RenderChannel( + JASDsp::TChannel& channel, + ChannelAuxData& channelAux, + OutputSubframe& subframe); + +/** + * Converts a pitch value on a DSP channel to a sample rate. + */ +constexpr static int PitchToSampleRate(u16 value) { + return static_cast(static_cast(SampleRate) * value / 4096); +} + +static void UpdateSampleRate(const JASDsp::TChannel& channel, ChannelAuxData& aux) { + auto sampleRate = PitchToSampleRate(channel.mPitch); + + const SDL_AudioSpec spec = { + SDL_AUDIO_S16, + 1, + sampleRate + }; + + SDL_SetAudioStreamFormat(aux.resampleStream, &spec, nullptr); + aux.prevPitch = channel.mPitch; +} + +/** + * Reset state for a DSP channel between independent playbacks. + */ +static void ResetChannel(JASDsp::TChannel& channel, ChannelAuxData& aux) { + aux.resetCount += 1; + + channel.mSamplesLeft = channel.mEndSample - channel.mSamplePosition; + + aux.hist0 = 0; + aux.hist1 = 0; + + SDL_ClearAudioStream(aux.resampleStream); + UpdateSampleRate(channel, aux); + + for (auto& volume : aux.prevVolume) { + volume = NAN; + } + + channel.mResetFlag = false; +} + +/** + * Mix subframe data from src into dst. + */ +static void MixSubframe(DspSubframe& dst, const DspSubframe& src) { + for (int i = 0; i < dst.size(); i++) { + dst[i] += src[i]; + } +} + +void dusk::audio::DspRender(OutputSubframe& subframe) { + std::span channels(JASDsp::CH_BUF, DSP_CHANNELS); + + for (int i = 0; i < channels.size(); i++) { + auto& channel = channels[i]; + auto& channelAux = ChannelAux[i]; + + if (!channel.mIsActive) { + continue; + } + + if (channel.mPauseFlag) { + // Not really sure what the practical difference between pause and + // deactivation is. Either avoids clearing state or allows the DSP to avoid popping? + continue; + } + + if (channel.mForcedStop) { + channel.mIsFinished = true; + continue; + } + + if (channel.mWaveAramAddress == 0) { + // I think these are oscillator channels? Not backed by audio. + // No idea how to implement these yet, so skip them. + channel.mIsFinished = true; + continue; + } + + ValidateChannel(channel); + + OutputSubframe channelSubframe = {}; + RenderChannel(channel, channelAux, channelSubframe); + + for (int o = 0; o < subframe.channels.size(); o++) { + MixSubframe(subframe.channels[o], channelSubframe.channels[o]); + } + } + + for (auto& channel : subframe.channels) { + ApplyVolume(channel, channel, PrevMasterVolume, MasterVolume); + } + PrevMasterVolume = MasterVolume; +} + +/** + * Actually decode samples from memory for the given audio channel. + */ +static void ReadSampleData( + const JASDsp::TChannel& channel, + ChannelAuxData& aux, + const u8* data, + size_t dataLength, + s16* pcm, + size_t pcmLength) { + if (channel.mSamplesPerBlock == 1) { + if (channel.mBytesPerBlock == 0x10) { + // PCM16 + assert(reinterpret_cast(data) % 2 == 0 && "PCM data must be aligned"); + assert(dataLength % 2 == 0 && "Data length must be multiple of 2"); + assert(dataLength * 2 >= pcmLength && "Input too small!"); + + auto srcPcm = reinterpret_cast(data); + for (size_t i = 0; i < pcmLength; i++) { + pcm[i] = srcPcm[i]; + } + } else { + CRASH("Unsupported format: PCM8"); + } + } else { + if (channel.mBytesPerBlock == 9) { + Adpcm4ToPcm16(data, dataLength, pcm, pcmLength, aux.hist1, aux.hist0); + } else { + CRASH("Unsupported format: ADPCM2"); + } + } +} + +/** + * Read a single *contiguous* chunk of sample data from a channel, + * writes the samples to the channel's resampler stream. + * + * @returns Amount of samples actually read. Can be greater than the amount requested. + */ +static int ReadChannelSamplesChunk( + JASDsp::TChannel& channel, + ChannelAuxData& aux, + int desiredSamples) { + + assert(desiredSamples >= 0); + + auto aramBase = static_cast(ARGetStorageAddress()) + channel.mWaveAramAddress; + + // Streaming logic directly modifies mSamplesLeft. + // So we use that as our tracking of where we are. + auto curSamplePosition = channel.mEndSample - channel.mSamplesLeft; + + u32 skipSamples = curSamplePosition % channel.mSamplesPerBlock; + if (skipSamples != 0) { + // We need to start reading in the middle of a block. This can happen thanks to loops. + // So we move back to the start of the block and keep track that those samples should + // *not* be emitted. + desiredSamples += static_cast(skipSamples); + curSamplePosition -= skipSamples; + + channel.mSamplesLeft += skipSamples; + channel.mSamplePosition -= skipSamples; + } + + // Pad desiredSamples so that we always leave the channel block-aligned. + desiredSamples = ALIGN_NEXT(desiredSamples, channel.mSamplesPerBlock); + + assert(curSamplePosition % channel.mSamplesPerBlock == 0); + auto dataPosition = ConvertSamplesToDataLength(channel, curSamplePosition); + + u32 renderSamples = std::min(channel.mSamplesLeft, static_cast(desiredSamples)); + + int renderSize = static_cast(sizeof(s16) * renderSamples); + auto renderData = static_cast(alloca(renderSize)); + memset(renderData, 0, renderSize); + + ReadSampleData( + channel, + aux, + aramBase + dataPosition, + ConvertSamplesToDataLength(channel, renderSamples), + renderData, + renderSamples); + + channel.mSamplesLeft -= renderSamples; + channel.mSamplePosition += renderSamples; + + SDL_PutAudioStreamData( + aux.resampleStream, + renderData + skipSamples, + static_cast(renderSize - skipSamples * sizeof(u16))); + + assert(channel.mSamplePosition % channel.mSamplesPerBlock == 0 || channel.mSamplesLeft == 0); + + return static_cast(renderSamples - skipSamples); +} + +/** + * Reads new audio channels from a DSP channel and writes them to the resampler stream. + */ +static void SDLCALL ReadChannelSamples( + void *userdata, + SDL_AudioStream*, + int additional_amount, + int) { + + if (additional_amount == 0) { + return; + } + + const auto index = static_cast(reinterpret_cast(userdata)); + auto& channel = JASDsp::CH_BUF[index]; + auto& aux = ChannelAux[index]; + + if (channel.mSamplesLeft == 0 && !channel.mLoopFlag) { + // May get called when we're out of data to read. + // This is expected, as we need to drain the resampler channel before we mark the channel as finished. + return; + } + + auto samplesRead = ReadChannelSamplesChunk(channel, aux, additional_amount); + additional_amount -= samplesRead; + + if (channel.mSamplesLeft == 0) { + // Reached end of buffer. + if (!channel.mLoopFlag) { + return; + } + + channel.mSamplesLeft = channel.mEndSample - channel.mLoopStartSample; + channel.mSamplePosition = channel.mLoopStartSample; + + aux.hist1 = channel.mpPenult; + aux.hist0 = channel.mpLast; + } + + if (additional_amount >= 0) { + ReadChannelSamplesChunk(channel, aux, additional_amount); + } + + channel.mAramStreamPosition = channel.mWaveAramAddress + + ConvertSamplesToDataLength(channel, channel.mSamplePosition); +} + +/** + * Get the expected BusConnect value needed to define the given output channel in a DSP channel. + */ +constexpr u16 GetBusConnect(const OutputChannel channel) { + switch (channel) { + // TODO: This is a guess for now. + case OutputChannel::LEFT: + return 0x0D00; + case OutputChannel::RIGHT: + return 0x0D60; + default: + CRASH("Invalid output channel!"); + } +} + +/** + * For a DSP channel the JASDsp::OutputChannelConfig value targeting the given output channel. + * Returns null if the DSP channel does not output to this output channel. + */ +static const JASDsp::OutputChannelConfig* GetOutputConfig( + const JASDsp::TChannel& sourceChannel, + OutputChannel channel) { + + auto busConnect = GetBusConnect(channel); + for (const auto& mOutputChannel : sourceChannel.mOutputChannels) { + auto config = &mOutputChannel; + if (config->mBusConnect == busConnect) { + return config; + } + } + + return nullptr; +} + +struct VolumeValue { + f32 Target; + f32 Init; +}; + +/** + * Get the volume that the given DSP channel should render to the given output channel at. + */ +static VolumeValue GetVolumeForOutputChannel( + const JASDsp::TChannel& sourceChannel, + OutputChannel outputChannel) { + + u16 volume; + u16 initVolume; + f32 panValue = 1; + if (sourceChannel.mAutoMixerBeenSet) { + volume = sourceChannel.mAutoMixerVolume; + initVolume = sourceChannel.mAutoMixerInitVolume; + + auto autoMixerPan = static_cast(sourceChannel.mAutoMixerPanDolby >> 8) / 127; + + switch (outputChannel) { + case OutputChannel::LEFT: + panValue = 1 - autoMixerPan; + break; + case OutputChannel::RIGHT: + panValue = autoMixerPan; + break; + default: + CRASH("Unhandled output channel: OutputChannel"); + } + + } else { + auto config = GetOutputConfig(sourceChannel, outputChannel); + if (config == nullptr) { + return {0, 0}; + } + + volume = config->mTargetVolume; + initVolume = config->mCurrentVolume; + } + + // TODO: interpolate to avoid popping. + f32 targetRatio = VolumeFromU16(volume); + targetRatio *= panValue; + + f32 initRatio = VolumeFromU16(initVolume); + initRatio *= panValue; + + return {targetRatio, initRatio}; +} + +/** + * Given decoded & resampled input samples, render a DSP channel to a given output channel. + */ +static void RenderOutputChannel( + const JASDsp::TChannel& sourceChannel, + ChannelAuxData& aux, + OutputChannel outputChannel, + const std::span inputSamples, + OutputSubframe& fullOutputSubframe) { + + auto& outputSubframe = fullOutputSubframe[outputChannel]; + assert(inputSamples.size() <= outputSubframe.size()); + + auto volume = GetVolumeForOutputChannel(sourceChannel, outputChannel); + + f32 targetVolume = volume.Target; + auto& prevVolume = aux.PrevVolume(outputChannel); + if (std::isnan(prevVolume)) { + // Initialize previous volume to new volume on first render. + prevVolume = volume.Init; + } + + if (prevVolume == 0 && targetVolume == 0) { + return; + } + + ApplyVolume(outputSubframe, inputSamples, prevVolume, targetVolume); + prevVolume = targetVolume; +} + +static void RenderChannel( + JASDsp::TChannel& channel, + ChannelAuxData& channelAux, + OutputSubframe& subframe) { + if (channel.mResetFlag) { + ResetChannel(channel, channelAux); + } else if (channelAux.prevPitch != channel.mPitch) { + UpdateSampleRate(channel, channelAux); + } + + DspSubframe audioLoadBuffer = {}; + + int wantRead = sizeof(audioLoadBuffer); + auto read = SDL_GetAudioStreamData( + channelAux.resampleStream, + &audioLoadBuffer, + wantRead); + + if (read < wantRead) { + channel.mIsFinished = true; + } + + auto hasReadSamples = std::span(audioLoadBuffer).subspan(0, wantRead / sizeof(f32)); + + static_assert(OutputSubframe::NUM_CHANNELS == 2, "Keep RenderChannel in sync!"); + + RenderOutputChannel(channel, channelAux, OutputChannel::LEFT, hasReadSamples, subframe); + RenderOutputChannel(channel, channelAux,OutputChannel::RIGHT, hasReadSamples, subframe); +} + +void dusk::audio::DspInit() { + constexpr SDL_AudioSpec srcSpec = { + SDL_AUDIO_S16, + 1, + SampleRate + }; + constexpr SDL_AudioSpec dstSpec = { + SDL_AUDIO_F32, + 1, + SampleRate + }; + + for (u32 i = 0; i < DSP_CHANNELS; i++) { + auto& aux = ChannelAux[i]; + aux.resampleStream = SDL_CreateAudioStream(&srcSpec, &dstSpec); + + SDL_SetAudioStreamGetCallback( + aux.resampleStream, + ReadChannelSamples, + reinterpret_cast(static_cast(i))); + } +} + +void dusk::audio::ApplyVolume( + std::span dst, + const std::span src, + const f32 startVolume, + const f32 endVolume) { + assert(dst.size() >= src.size()); + + if (startVolume == endVolume) { + for (int i = 0; i < src.size(); i++) { + dst[i] = src[i] * startVolume; + } + } else { + const f32 step = (endVolume - startVolume) / static_cast(src.size()); + auto curVolume = startVolume; + for (int i = 0; i < src.size(); i++) { + dst[i] = src[i] * curVolume; + curVolume += step; + } + } +} diff --git a/src/dusk/audio/DuskDsp.hpp b/src/dusk/audio/DuskDsp.hpp new file mode 100644 index 0000000000..c84bb338db --- /dev/null +++ b/src/dusk/audio/DuskDsp.hpp @@ -0,0 +1,112 @@ +#pragma once + +#include "JSystem/JAudio2/JASDSPInterface.h" + +#include +#include + +#include "SDL3/SDL_audio.h" +#include + +// ReSharper disable once CppUnusedIncludeDirective +#include "global.h" + +namespace dusk::audio { + constexpr int SampleRate = 32000; + + enum class OutputChannel : u8 { + LEFT, + RIGHT, + OutputChannel_MAX + }; + + /** + * Data stored by DSP implementation for each DSP channel. + */ + struct ChannelAuxData { + s16 hist1; + s16 hist0; + SDL_AudioStream* resampleStream; + u16 prevPitch; + + // Used for debugging tools. + u32 resetCount; + + /** + * Previous volume values, per output channel. + * Used to avoid clicking when volumes change. + * Set to NaN after channel reset, indicating that initial volume value is previous. + */ + f32 prevVolume[static_cast(OutputChannel::OutputChannel_MAX)]; + + f32& PrevVolume(OutputChannel channel) { + assert(channel < OutputChannel::OutputChannel_MAX); + return prevVolume[static_cast(channel)]; + } + }; + + extern ChannelAuxData ChannelAux[DSP_CHANNELS]; + + /** + * Data storage for a single subframe and output channel's worth of samples. + */ + using DspSubframe = std::array; + + /** + * Data storage for a single subframe's worth of samples, across all output channels. + */ + struct OutputSubframe { + static constexpr int NUM_CHANNELS = static_cast(OutputChannel::OutputChannel_MAX); + + std::array channels; + + DspSubframe& operator[](OutputChannel channel) { + assert(channel < OutputChannel::OutputChannel_MAX); + return channels[static_cast(channel)]; + } + }; + + /** + * Initialize the DSP system, creating data storage needed for channels and such. + */ + void DspInit(); + + /** + * Render a subframe of audio with the current DSP state. + */ + void DspRender(OutputSubframe& subframe); + + /** + * Get the amount of samples a single "block" of this channel's data has. + */ + constexpr u32 BlockSamples(const JASDsp::TChannel& channel) { + return channel.mSamplesPerBlock; + } + + /** + * Get the amount of bytes a single "block" of this channel's data has. + */ + constexpr u32 BlockBytes(const JASDsp::TChannel& channel) { + if (channel.mSamplesPerBlock == 1) { + if (channel.mBytesPerBlock == 16) { + return 2; + } + if (channel.mBytesPerBlock == 8) { + return 1; + } + + CRASH("Unknown format"); + } + + return channel.mBytesPerBlock; + } + + /** + * Apply a volume level to audio data. + * Interpolates across the two provided volume levels to avoid clicking. + */ + void ApplyVolume(std::span dst, std::span src, f32 startVolume, f32 endVolume); + + extern f32 MasterVolume; + extern f32 PrevMasterVolume; +} diff --git a/src/dusk/audio/JASCriticalSection.cpp b/src/dusk/audio/JASCriticalSection.cpp new file mode 100644 index 0000000000..9b315b9d0b --- /dev/null +++ b/src/dusk/audio/JASCriticalSection.cpp @@ -0,0 +1,13 @@ +#include "JSystem/JAudio2/JASCriticalSection.h" + +#include + +static std::recursive_mutex gAudioThreadMutex; + +JASCriticalSection::JASCriticalSection() { + gAudioThreadMutex.lock(); +} + +JASCriticalSection::~JASCriticalSection() { + gAudioThreadMutex.unlock(); +} diff --git a/src/dusk/imgui/ImGuiAudio.cpp b/src/dusk/imgui/ImGuiAudio.cpp new file mode 100644 index 0000000000..707091b158 --- /dev/null +++ b/src/dusk/imgui/ImGuiAudio.cpp @@ -0,0 +1,252 @@ +#include "ImGuiConsole.hpp" +#include "ImGuiMenuTools.hpp" +#include "JSystem/JAudio2/JAISeMgr.h" +#include "JSystem/JAudio2/JAISeqMgr.h" +#include "JSystem/JAudio2/JAIStreamMgr.h" +#include "JSystem/JAudio2/JASCriticalSection.h" +#include "JSystem/JAudio2/JASDSPChannel.h" +#include "JSystem/JAudio2/JASDSPInterface.h" +#include "JSystem/JAudio2/JASTrack.h" +#include "dusk/audio/DuskAudioSystem.h" + +static std::array channelSortIndices = {}; +static std::array lastResetCounts = {}; + +static bool sortUpdateCount = true; + +static void DisplayDspChannel(int i) { + using namespace dusk::audio; + + auto& channel = JASDsp::CH_BUF[i]; + auto& jasChannel = JASDSPChannel::sDspChannels[i]; + if (!channel.mIsActive) { + return; + } + + char buf[64]; + snprintf(buf, sizeof(buf), "%d", i); + + if (ImGui::BeginChild(buf, ImVec2(), ImGuiChildFlags_Border | ImGuiChildFlags_AutoResizeY)) { + ImGui::Text("[%02X]", i); + ImGui::SameLine(); + + auto resetCount = GetResetCount(i); + ImColor color = IM_COL32_WHITE; + if (lastResetCounts[i] != resetCount) { + lastResetCounts[i] = resetCount; + color = IM_COL32(0, 0xFF, 0, 0xFF); + } + ImGui::TextColored(color, "Update count: %d, reset count: %ud", jasChannel.mUpdateCounter, resetCount); + ImGui::TextUnformatted(channel.mLoopFlag ? "Loop: true" : "Loop: false"); + ImGui::SameLine(); + ImGui::Text("Priority: %hd", jasChannel.mPriority); + ImGui::Text("Format: %02X/%02X", channel.mSamplesPerBlock, channel.mBytesPerBlock); + ImGui::Text("Position: %08X/%08X", channel.mSamplePosition, channel.mEndSample); + ImGui::SameLine(); + ImGui::Text("Memory: %08X/%08X", channel.mWaveAramAddress, channel.mAramStreamPosition); + + if (channel.mAutoMixerBeenSet) { + auto pan = (channel.mAutoMixerPanDolby >> 8) / 127.5f; + auto dolby = (channel.mAutoMixerPanDolby & 0xFF) / 127.5f; + auto fxMix = (channel.mAutoMixerFxMix >> 8) / 127.5f; + auto volume = VolumeFromU16(channel.mAutoMixerVolume); + ImGui::Text( + "Auto mixer active (pan: %f, dolby: %f, fx: %f, volume: %f)", + pan, dolby, fxMix, volume); + } else { + ImGui::Text( + "Bus connect: %04X(%.2f),%04X(%.2f),%04X(%.2f),%04X(%.2f),%04X(%.2f),%04X(%.2f)", + channel.mOutputChannels[0].mBusConnect, + VolumeFromU16(channel.mOutputChannels[0].mTargetVolume), + channel.mOutputChannels[1].mBusConnect, + VolumeFromU16(channel.mOutputChannels[1].mTargetVolume), + channel.mOutputChannels[2].mBusConnect, + VolumeFromU16(channel.mOutputChannels[2].mTargetVolume), + channel.mOutputChannels[3].mBusConnect, + VolumeFromU16(channel.mOutputChannels[3].mTargetVolume), + channel.mOutputChannels[4].mBusConnect, + VolumeFromU16(channel.mOutputChannels[4].mTargetVolume), + channel.mOutputChannels[5].mBusConnect, + VolumeFromU16(channel.mOutputChannels[5].mTargetVolume)); + } + } + + ImGui::EndChild(); +} + +static void InitChannelSortIndices() { + for (int i = 0; i < channelSortIndices.size(); i++) { + channelSortIndices[i] = i; + } +} + +static void SortChannelsByUpdateCount() { + InitChannelSortIndices(); + std::ranges::stable_sort( + channelSortIndices, + [](u8 a, u8 b) { + auto& jasChannelA = JASDSPChannel::sDspChannels[a]; + auto& jasChannelB = JASDSPChannel::sDspChannels[b]; + + return jasChannelA.mUpdateCounter > jasChannelB.mUpdateCounter; + }); +} + +static void ShowAllDspChannels() { + int activeChannels = 0; + for (int i = 0; i < DSP_CHANNELS; i++) { + if (JASDsp::CH_BUF[i].mIsActive) { + activeChannels++; + } + } + + ImGui::Text("Active channels: %d", activeChannels); + ImGui::Checkbox("Sort by update count", &sortUpdateCount); + + if (sortUpdateCount) { + SortChannelsByUpdateCount(); + for (u8 index : channelSortIndices) { + DisplayDspChannel(index); + } + } else { + for (int i = 0; i < DSP_CHANNELS; i++) { + DisplayDspChannel(i); + } + } +} + +static void ShowAllTracks() { + if (ImGui::Button("Pause all")) { + for (auto& track : JASTrack::sTrackList) { + track.pause(true); + } + } + + for (auto& track : JASTrack::sTrackList) { + char buf[32]; + snprintf(buf, sizeof(buf), "%p", &track); + + if (ImGui::BeginChild(buf, ImVec2(), ImGuiChildFlags_Border | ImGuiChildFlags_AutoResizeY)) { + ImGui::Text("[%p]", &track); + bool paused = track.mFlags.pause; + ImGui::Checkbox("Paused", &paused); + track.mFlags.pause = paused; + bool muted = track.mFlags.mute; + ImGui::Checkbox("Muted", &muted); + track.mFlags.mute = muted; + + for (int i = 0; i < JASTrack::MAX_CHILDREN; i++) { + const auto child = track.getChild(i); + if (child != nullptr) { + ImGui::Text("child: [%p]", child); + } + } + } + + ImGui::EndChild(); + } +} + +static void ShowAllJAIStreams() { + auto& mgr = *JAIStreamMgr::getInstance(); + + for (auto streamLink = mgr.getStreamList()->getFirst(); streamLink != nullptr; streamLink = streamLink->getNext()) { + auto& stream = *streamLink->getObject(); + char buf[32]; + snprintf(buf, sizeof(buf), "%p", &stream); + + if (ImGui::BeginChild(buf, ImVec2(), ImGuiChildFlags_Border | ImGuiChildFlags_AutoResizeY)) { + ImGui::Text("[%p]", &stream); + bool paused = stream.status_.field_0x0.flags.paused; + ImGui::Checkbox("Paused", &paused); + stream.status_.field_0x0.flags.paused = paused; + } + + ImGui::EndChild(); + } +} + +static void ShowAllJAISes() { + auto& mgr = *JAISeMgr::getInstance(); + + for (int i = 0; i < JAISeMgr::NUM_CATEGORIES; i++) { + const auto category = mgr.getCategory(i); + + char buf[32]; + snprintf(buf, sizeof(buf), "%i", i); + + if (ImGui::BeginChild(buf, ImVec2(), ImGuiChildFlags_Border | ImGuiChildFlags_AutoResizeY)) { + ImGui::Text("Category: %i", i); + if (ImGui::Button("Pause All")) { + category->pause(true); + } + + for (auto seLink = category->getSeList()->getFirst(); seLink != nullptr; seLink = seLink->getNext()) { + const auto se = seLink->getObject(); + ImGui::Text("[%p]", se); + ImGui::Text(se->status_.field_0x0.flags.paused ? "Paused" : "Not paused"); + } + } + + ImGui::EndChild(); + } +} + + +static void ShowAllJAISeqs() { + auto& mgr = *JAISeqMgr::getInstance(); + + if (ImGui::Button("Pause")) { + mgr.pause(true); + } + ImGui::SameLine(); + if (ImGui::Button("Unpause")) { + mgr.pause(false); + } +} + +void dusk::ImGuiMenuTools::ShowAudioDebug() { + if (!ImGuiConsole::CheckMenuViewToggle(ImGuiKey_F7, m_showAudioDebug)) { + return; + } + + if (!ImGui::Begin("Audio Debug", &m_showAudioDebug)) { + ImGui::End(); + return; + } + + { + JASCriticalSection cs; + + if (ImGui::BeginTabBar("Tabs")) { + if (ImGui::BeginTabItem("DSP channels")) { + ShowAllDspChannels(); + ImGui::EndTabItem(); + } + + if (ImGui::BeginTabItem("JAITrack")) { + ShowAllTracks(); + ImGui::EndTabItem(); + } + + if (ImGui::BeginTabItem("JAIStream")) { + ShowAllJAIStreams(); + ImGui::EndTabItem(); + } + + if (ImGui::BeginTabItem("JAISe")) { + ShowAllJAISes(); + ImGui::EndTabItem(); + } + + if (ImGui::BeginTabItem("JAISeq")) { + ShowAllJAISeqs(); + ImGui::EndTabItem(); + } + + ImGui::EndTabBar(); + } + } + + ImGui::End(); +} \ No newline at end of file diff --git a/src/dusk/imgui/ImGuiMenuGame.cpp b/src/dusk/imgui/ImGuiMenuGame.cpp index 79dfcb022d..e4ff609ccb 100644 --- a/src/dusk/imgui/ImGuiMenuGame.cpp +++ b/src/dusk/imgui/ImGuiMenuGame.cpp @@ -7,8 +7,9 @@ #include #include "JSystem/JUtility/JUTGamePad.h" -#include "m_Do/m_Do_controller_pad.h" +#include "dusk/audio/DuskAudioSystem.h" #include "m_Do/m_Do_audio.h" +#include "m_Do/m_Do_controller_pad.h" namespace dusk { ImGuiMenuGame::ImGuiMenuGame() {} @@ -35,6 +36,8 @@ namespace dusk { ImGui::Text("Master Volume"); ImGui::SliderFloat("##m_masterVolume", &m_audioSettings.m_masterVolume, 0.0f, 1.0f, ""); + /* + // TODO: implement additional settings ImGui::Text("Main Music Volume"); ImGui::SliderFloat("##m_mainMusicVolume", &m_audioSettings.m_mainMusicVolume, 0.0f, 1.0f, ""); @@ -49,8 +52,10 @@ namespace dusk { Z2AudioMgr* audioMgr = Z2AudioMgr::getInterface(); if (audioMgr != nullptr) { - // TODO: actually apply volume settings } + */ + + audio::SetMasterVolume(m_audioSettings.m_masterVolume); ImGui::EndMenu(); } diff --git a/src/dusk/imgui/ImGuiMenuTools.cpp b/src/dusk/imgui/ImGuiMenuTools.cpp index e84dbc1f08..e77941af52 100644 --- a/src/dusk/imgui/ImGuiMenuTools.cpp +++ b/src/dusk/imgui/ImGuiMenuTools.cpp @@ -20,7 +20,7 @@ namespace dusk { if (ImGui::Checkbox("Development Mode", &m_isDevelopmentMode)) { isToggleDevelopmentMode = true; } - + ImGui::Separator(); if (ImGui::BeginMenu("Collision View")) { @@ -45,6 +45,7 @@ namespace dusk { ImGui::MenuItem("Map Loader", nullptr, &m_showMapLoader); ImGui::MenuItem("Player Info", nullptr, &m_showPlayerInfo); ImGui::MenuItem("Save Editor", nullptr, &m_showSaveEditor); + ImGui::MenuItem("Audio Debug", "F7", &m_showAudioDebug); ImGui::EndMenu(); } @@ -59,6 +60,7 @@ namespace dusk { ShowStubLog(); ShowMapLoader(); ShowPlayerInfo(); + ShowAudioDebug(); if (m_showSaveEditor) { m_saveEditor.draw(m_showSaveEditor); diff --git a/src/dusk/imgui/ImGuiMenuTools.hpp b/src/dusk/imgui/ImGuiMenuTools.hpp index 325181268a..35703d8aa2 100644 --- a/src/dusk/imgui/ImGuiMenuTools.hpp +++ b/src/dusk/imgui/ImGuiMenuTools.hpp @@ -31,6 +31,7 @@ namespace dusk { void ShowStubLog(); void ShowMapLoader(); void ShowPlayerInfo(); + void ShowAudioDebug(); CollisionViewSettings& getCollisionViewSettings() { return m_collisionViewSettings; } @@ -48,6 +49,8 @@ namespace dusk { bool m_showStubLog = false; bool m_showMapLoader = false; + + bool m_showAudioDebug = false; struct { int mapIdx = -1; int regionIdx = -1; diff --git a/src/dusk/imgui/ImGuiStubLog.cpp b/src/dusk/imgui/ImGuiStubLog.cpp index 0876125865..5f77dccd38 100644 --- a/src/dusk/imgui/ImGuiStubLog.cpp +++ b/src/dusk/imgui/ImGuiStubLog.cpp @@ -1,4 +1,5 @@ #include +#include #include "dusk/logging.h" #include "imgui.h" @@ -9,6 +10,7 @@ namespace dusk { static ImGuiTextBuffer StubLogBuffer; static std::vector LineOffsets; static bool StubLogPaused; + static std::mutex StubLogMutex; const char* LogLevelName(const AuroraLogLevel level) { switch (level) { @@ -32,6 +34,8 @@ namespace dusk { return; } + std::lock_guard lock(StubLogMutex); + LineOffsets.push_back(StubLogBuffer.size()); const auto levelName = LogLevelName(level); StubLogBuffer.appendf("[%s | %s] %s\n", levelName, module, message); @@ -40,6 +44,8 @@ namespace dusk { static void ClearPastFrame(); void ImGuiMenuTools::ShowStubLog() { + std::lock_guard lock(StubLogMutex); + if (!ImGuiConsole::CheckMenuViewToggle(ImGuiKey_F5, m_showStubLog)) { ClearPastFrame(); return; @@ -56,7 +62,7 @@ namespace dusk { if (ImGui::BeginChild("scrolling")) { ImGuiListClipper clipper; - clipper.Begin(LineOffsets.size()); + clipper.Begin(static_cast(LineOffsets.size())); while (clipper.Step()) { for (int idx = clipper.DisplayStart; idx < clipper.DisplayEnd; idx++) { const char* lineStart = StubLogBuffer.begin() + LineOffsets[idx]; diff --git a/src/dusk/stubs.cpp b/src/dusk/stubs.cpp index 6a5a8f86e1..4e259ff97e 100644 --- a/src/dusk/stubs.cpp +++ b/src/dusk/stubs.cpp @@ -367,46 +367,6 @@ VIRetraceCallback VISetPreRetraceCallback(VIRetraceCallback cb) { } // extern "C" -#pragma mark DSP -#include -extern "C" void __DSP_insert_task(DSPTaskInfo* task) { - STUB_LOG(); -} - -extern "C" void __DSP_boot_task(DSPTaskInfo*) { - STUB_LOG(); -} - -extern "C" void __DSP_exec_task(DSPTaskInfo*, DSPTaskInfo*) { - STUB_LOG(); -} - -extern "C" void __DSP_remove_task(DSPTaskInfo* task) { - STUB_LOG(); -} - -void DSPAssertInt(void) { - STUB_LOG(); -} -u32 DSPCheckMailFromDSP(void) { - STUB_LOG(); - return 0; -} -u32 DSPCheckMailToDSP(void) { - STUB_LOG(); - return 0; -} -void DSPInit(void) { - STUB_LOG(); -} -u32 DSPReadMailFromDSP(void) { - STUB_LOG(); - return 0; -} -void DSPSendMailToDSP(u32 mail) { - STUB_LOG(); -} - #pragma mark Z2Audio class Z2AudioCS { public: diff --git a/src/f_op/f_op_actor_mng.cpp b/src/f_op/f_op_actor_mng.cpp index 79795d3bfe..36217076bf 100644 --- a/src/f_op/f_op_actor_mng.cpp +++ b/src/f_op/f_op_actor_mng.cpp @@ -1019,10 +1019,15 @@ cull_sphere l_cullSizeSphere[fopAc_CULLSPHERE_MAX_e] = { s32 fopAcM_cullingCheck(fopAc_ac_c const* i_actor) { MtxP mtx_p; +#if AVOID_UB + Mtx concat_mtx; +#endif if (fopAcM_GetMtx(i_actor) == NULL) { mtx_p = j3dSys.getViewMtx(); } else { +#if !AVOID_UB Mtx concat_mtx; +#endif cMtx_concat(j3dSys.getViewMtx(), fopAcM_GetMtx(i_actor), concat_mtx); mtx_p = concat_mtx; } diff --git a/src/m_Do/m_Do_DVDError.cpp b/src/m_Do/m_Do_DVDError.cpp index 4984ea22c7..62fd71ed21 100644 --- a/src/m_Do/m_Do_DVDError.cpp +++ b/src/m_Do/m_Do_DVDError.cpp @@ -14,6 +14,8 @@ #include #include +#include "dusk/os.h" + #if PLATFORM_GCN const int stack_size = 3072; #else @@ -65,6 +67,11 @@ static void mDoDvdErr_Watch(void*) { OSDisableInterrupts(); #endif #endif + +#if TARGET_PC + OSSetCurrentThreadName("DVD error thread"); +#endif + JKRThread(OSGetCurrentThread(), 0); JKRSetCurrentHeap(mDoExt_getAssertHeap()); diff --git a/src/m_Do/m_Do_MemCard.cpp b/src/m_Do/m_Do_MemCard.cpp index 919774d2e0..bbb94f2bcd 100644 --- a/src/m_Do/m_Do_MemCard.cpp +++ b/src/m_Do/m_Do_MemCard.cpp @@ -10,6 +10,7 @@ #include "m_Do/m_Do_MemCardRWmng.h" #include "m_Do/m_Do_Reset.h" #include "os_report.h" +#include "dusk/os.h" #if PLATFORM_WII || PLATFORM_SHIELD #include @@ -866,6 +867,10 @@ mDoMemCd_Ctrl_c g_mDoMemCd_control; static int mDoMemCd_main(void*) { JKRThread(OSGetCurrentThread(), 0); +#if TARGET_PC + OSSetCurrentThreadName("MemCardThread"); +#endif + JKRSetCurrentHeap(mDoExt_getAssertHeap()); g_mDoMemCd_control.main(); diff --git a/src/m_Do/m_Do_dvd_thread.cpp b/src/m_Do/m_Do_dvd_thread.cpp index 8949988c7c..08197ed30b 100644 --- a/src/m_Do/m_Do_dvd_thread.cpp +++ b/src/m_Do/m_Do_dvd_thread.cpp @@ -10,6 +10,7 @@ #include "JSystem/JKernel/JKRDvdRipper.h" #include "JSystem/JKernel/JKRExpHeap.h" #include "JSystem/JKernel/JKRMemArchive.h" +#include "dusk/os.h" #include "m_Do/m_Do_Reset.h" #include "m_Do/m_Do_controller_pad.h" #include "m_Do/m_Do_ext.h" @@ -17,6 +18,9 @@ s32 mDoDvdThd::main(void* param_0) { JKRThread(OSGetCurrentThread(), 0); +#if TARGET_PC + OSSetCurrentThreadName("DVD thread"); +#endif JKRSetCurrentHeap(mDoExt_getAssertHeap()); mDoDvdThd_param_c* param = static_cast(param_0); param->mainLoop(); @@ -159,7 +163,11 @@ void mDoDvdThd_param_c::mainLoop() { while ((command = this->getFirstCommand())) { this->cut(command); if (mDoDvdThd::SyncWidthSound) { + #if TARGET_PC + JASDvd::getThreadPointer()->sendCmdMsg(cb, &command, sizeof(void*)); + #else JASDvd::getThreadPointer()->sendCmdMsg(cb, &command, 4); + #endif } else { cb(&command); } diff --git a/src/m_Do/m_Do_main.cpp b/src/m_Do/m_Do_main.cpp index a2fe24771d..b3fb05b0b9 100644 --- a/src/m_Do/m_Do_main.cpp +++ b/src/m_Do/m_Do_main.cpp @@ -47,6 +47,7 @@ #include "dusk/dusk.h" #include "dusk/logging.h" #include "dusk/time.h" +#include "dusk/main.h" #include #include @@ -73,6 +74,10 @@ const int audioHeapSize = 0x14D800; // ========================================================================= #define COPYDATE_PATH "/str/Final/Release/COPYDATE" +#if TARGET_PC +bool dusk::IsShuttingDown = false; +#endif + s32 LOAD_COPYDATE(void*) { char buffer[32]; memset(buffer, 0, sizeof(buffer)); @@ -307,6 +312,8 @@ int game_main(int argc, char* argv[]) { fflush(stdout); fflush(stderr); + dusk::IsShuttingDown = true; + aurora_shutdown(); return 0;