mirror of
https://github.com/TwilitRealm/dusklight
synced 2026-05-31 00:45:24 -04:00
+10
-3
@@ -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 $<$<CONFIG:Debug>: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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include <dolphin/types.h>
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
#ifndef DUSK_MAIN_H
|
||||
#define DUSK_MAIN_H
|
||||
|
||||
namespace dusk {
|
||||
extern bool IsShuttingDown;
|
||||
}
|
||||
|
||||
#endif // DUSK_MAIN_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
|
||||
@@ -0,0 +1,58 @@
|
||||
#ifndef DUSK_STRING_HPP
|
||||
#define DUSK_STRING_HPP
|
||||
|
||||
#include "global.h"
|
||||
#include <cstring>
|
||||
#include <dolphin/os.h>
|
||||
|
||||
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 <size_t BufSize>
|
||||
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 <size_t BufSize>
|
||||
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
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
+8
-2
@@ -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
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "JSystem/JAudio2/JAIAudible.h"
|
||||
#include "JSystem/JUtility/JUTAssert.h"
|
||||
#include "global.h"
|
||||
#include "dusk/endian.h"
|
||||
#include <cstdint>
|
||||
|
||||
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_;
|
||||
};
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "JSystem/JAudio2/JASTaskThread.h"
|
||||
#include "JSystem/JUtility/JUTAssert.h"
|
||||
#include <dvd.h>
|
||||
#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;
|
||||
};
|
||||
|
||||
|
||||
@@ -32,11 +32,6 @@ struct JASAudioThread : public JKRThread, public JASGlobalInstance<JASAudioThrea
|
||||
|
||||
static volatile int snIntCount; // type unsure
|
||||
|
||||
#if TARGET_PC
|
||||
static bool sThreadInitComplete;
|
||||
static OSMutex sThreadInitCompleteMutex;
|
||||
static OSCond sThreadInitCompleteCond;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif /* JASAUDIOTHREAD_H */
|
||||
|
||||
@@ -10,21 +10,21 @@ class JKRHeap;
|
||||
|
||||
namespace JASBNKParser {
|
||||
struct TFileHeader {
|
||||
/* 0x0 */ BE(int) id;
|
||||
/* 0x0 */ BE(int) mMagic;
|
||||
/* 0x4 */ BE(u32) mSize;
|
||||
/* 0x8 */ u8 _08[4];
|
||||
/* 0x8 */ BE(u32) mGlobalId;
|
||||
/* 0xC */ BE(u32) mVersion;
|
||||
};
|
||||
|
||||
namespace Ver1 {
|
||||
struct TOsc {
|
||||
/* 0x00 */ BE(u32) id;
|
||||
/* 0x00 */ BE(u32) id; // "Osci"
|
||||
/* 0x04 */ u8 mTarget;
|
||||
/* 0x08 */ BE(f32) _08;
|
||||
/* 0x0C */ BE(u32) mTableOffset;
|
||||
/* 0x10 */ BE(u32) _10;
|
||||
/* 0x14 */ BE(f32) mScale;
|
||||
/* 0x18 */ BE(f32) _18;
|
||||
/* 0x08 */ BE(f32) mRate;
|
||||
/* 0x0C */ BE(u32) mAttackEnvelopeOffset;
|
||||
/* 0x10 */ BE(u32) mReleaseEnvelopeOffset;
|
||||
/* 0x14 */ BE(f32) mScale; // width
|
||||
/* 0x18 */ BE(f32) mVertex;
|
||||
};
|
||||
|
||||
struct TPercData {
|
||||
@@ -36,7 +36,7 @@ namespace JASBNKParser {
|
||||
};
|
||||
|
||||
struct TChunk {
|
||||
/* 0x0 */ BE(u32) mID;
|
||||
/* 0x0 */ BE(u32) mID; // Magic
|
||||
/* 0x4 */ BE(u32) mSize;
|
||||
};
|
||||
|
||||
@@ -113,7 +113,7 @@ namespace JASBNKParser {
|
||||
};
|
||||
|
||||
struct TOffsetData {
|
||||
/* 0x000 */ u8 field_0x20[4];
|
||||
/* 0x000 */ BE(u32) mMagic; // 'BANK'
|
||||
/* 0x004 */ TOffset<TInst> mInstOffset[0x80];
|
||||
/* 0x204 */ u8 field_0x204[0x190];
|
||||
/* 0x394 */ TOffset<TPerc> mPercOffset[12];
|
||||
|
||||
@@ -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 <typename A, typename B>
|
||||
|
||||
@@ -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 <os.h>
|
||||
|
||||
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<JASChannel> {
|
||||
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];
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -4,6 +4,21 @@
|
||||
#include <cstdint>
|
||||
#include <types.h>
|
||||
|
||||
/**
|
||||
* 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*));
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -352,6 +352,28 @@ template <typename T> JASMemPool<T> JASPoolAllocObject<T>::memPool_;
|
||||
template <typename T>
|
||||
class JASMemPool_MultiThreaded : public JASGenericMemPool {
|
||||
public:
|
||||
#if TARGET_PC
|
||||
OSMutex mutex;
|
||||
|
||||
JASMemPool_MultiThreaded() {
|
||||
OSInitMutex(&mutex);
|
||||
}
|
||||
|
||||
void newMemPool(int param_0) {
|
||||
JASThreadingModel::ObjectLevelLockable<OSMutex>::Lock lock(mutex);
|
||||
JASGenericMemPool::newMemPool(sizeof(T), param_0);
|
||||
}
|
||||
|
||||
void* alloc(size_t count) {
|
||||
JASThreadingModel::ObjectLevelLockable<OSMutex>::Lock lock(mutex);
|
||||
return JASGenericMemPool::alloc(count);
|
||||
}
|
||||
|
||||
void free(void* ptr, u32 param_1) {
|
||||
JASThreadingModel::ObjectLevelLockable<OSMutex>::Lock lock(mutex);
|
||||
JASGenericMemPool::free(ptr, param_1);
|
||||
}
|
||||
#else
|
||||
void newMemPool(int param_0) {
|
||||
typename JASThreadingModel::InterruptsDisable<JASMemPool_MultiThreaded<T> >::Lock lock(*this);
|
||||
JASGenericMemPool::newMemPool(sizeof(T), param_0);
|
||||
@@ -366,6 +388,7 @@ public:
|
||||
typename JASThreadingModel::InterruptsDisable<JASMemPool_MultiThreaded<T> >::Lock lock(*this);
|
||||
JASGenericMemPool::free(ptr, param_1);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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() {}
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
|
||||
#include <types.h>
|
||||
|
||||
#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 */
|
||||
|
||||
@@ -54,7 +54,7 @@ struct JASTrack : public JASPoolAllocObject_MultiThreaded<JASTrack> {
|
||||
/* 0x4c */ JASTrack* mTrack;
|
||||
};
|
||||
|
||||
struct TList : JGadget::TLinkList<JASTrack, JASTrackNodeOffset> {
|
||||
struct TList : JGadget::TLinkList<JASTrack, -JASTrackNodeOffset> {
|
||||
TList() : mCallbackRegistered(false) {}
|
||||
void append(JASTrack*);
|
||||
void seqMain();
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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<TWave> mWaveOffsets[0];
|
||||
};
|
||||
|
||||
struct TWaveArchiveBank {
|
||||
/* 0x0 */ u8 _00[8];
|
||||
/* 0x0 */ BE(u32) mMagic; // 'WINF'
|
||||
/* 0x0 */ BE(u32) mArchiveCounts;
|
||||
/* 0x8 */ TOffset<TWaveArchive> 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<TCtrlScene> 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<TWaveArchiveBank> mArchiveBankOffset;
|
||||
/* 0x14 */ TOffset<TCtrlGroup> mCtrlGroupOffset;
|
||||
|
||||
@@ -3,7 +3,12 @@
|
||||
|
||||
#include <types.h>
|
||||
|
||||
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;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#define JAUAUDIBLEPARAM_H
|
||||
|
||||
#include <types.h>
|
||||
#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;
|
||||
};
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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_;
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -48,13 +48,13 @@ template <size_t MAX_CHUNKS_>
|
||||
class JAUStreamStaticAramMgr_ : public JAUStreamAramMgrBase_<MAX_CHUNKS_> {
|
||||
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;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include <types.h>
|
||||
|
||||
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);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
#include <types.h>
|
||||
|
||||
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));
|
||||
|
||||
|
||||
@@ -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<>
|
||||
|
||||
@@ -132,6 +132,10 @@ public:
|
||||
|
||||
static JSUList<JKRThread> sThreadList;
|
||||
// static u8 sThreadList[12];
|
||||
|
||||
#if TARGET_PC
|
||||
const char* mThreadName;
|
||||
#endif
|
||||
};
|
||||
|
||||
class JKRIdleThread : public JKRThread {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 ));
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ void JAISeq::JAISeqMgr_startID_(JAISoundID id, const JGeometry::TVec3<f32>* 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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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; i<DSP_CHANNELS; i++) {
|
||||
JASDSPChannel* handle = JASDSPChannel::getHandle(i);
|
||||
if (handle->getStatus() == 0) {
|
||||
handle->drop();
|
||||
|
||||
@@ -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<JASChannel>
|
||||
void* JASAudioThread::run() {
|
||||
#if !TARGET_PC
|
||||
OSInitFastCast();
|
||||
JASDriver::initAI(DMACallback);
|
||||
JASDsp::boot(DSPCallback);
|
||||
@@ -79,13 +76,6 @@ void* JASAudioThread::run() {
|
||||
JASPoolAllocObject_MultiThreaded<JASChannel>::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
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<f32>::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<f32>::PI() * 0.5f);
|
||||
|
||||
@@ -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++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -27,6 +27,10 @@ JSUList<JKRAMCommand> 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<u8*>(source);
|
||||
}
|
||||
#endif
|
||||
|
||||
OSSendMessage(&JKRAram::sMessageQueue, message, OS_MESSAGE_BLOCK);
|
||||
if (command->mCallback != NULL) {
|
||||
sAramPieceCommandList.append(&command->mPieceLink);
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
#include "JSystem/JUtility/JUTAssert.h"
|
||||
#include "JSystem/JUtility/JUTException.h"
|
||||
#include "dusk/string.hpp"
|
||||
#ifdef __MWERKS__
|
||||
#include <stdint.h>
|
||||
#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, ...) {
|
||||
|
||||
@@ -7,6 +7,10 @@
|
||||
#include "global.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#if TARGET_PC
|
||||
#include "dusk/os.h"
|
||||
#endif
|
||||
|
||||
JSUList<JKRThread> 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<JKRThread*>(thread);
|
||||
if (thd.mThreadName == nullptr) {
|
||||
thd.mThreadName = typeid(thd).name();
|
||||
}
|
||||
OSSetCurrentThreadName(thd.mThreadName);
|
||||
#endif
|
||||
|
||||
return ((JKRThread*)thread)->run();
|
||||
}
|
||||
|
||||
|
||||
@@ -552,7 +552,11 @@ JAIAudible* Z2Audience::newAudible(const JGeometry::TVec3<f32>& pos, JAISoundID
|
||||
}
|
||||
|
||||
void Z2Audience::deleteAudible(JAIAudible* audible) {
|
||||
#if TARGET_PC
|
||||
JKR_DELETE(static_cast<Z2Audible*>(audible));
|
||||
#else
|
||||
JKR_DELETE(audible);
|
||||
#endif
|
||||
}
|
||||
|
||||
Z2Audible::~Z2Audible() {}
|
||||
|
||||
@@ -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<Z2SoundHandlePool>::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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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<JAUSectionHeap>::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<JAUSectionHeap>::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;
|
||||
} */
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ Z2SoundHandlePool* Z2SoundHandles::getHandleSoundID(JAISoundID soundID) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Z2SoundHandlePool* Z2SoundHandles::getHandleUserData(u32 userData) {
|
||||
Z2SoundHandlePool* Z2SoundHandles::getHandleUserData(uintptr_t userData) {
|
||||
JSULink<Z2SoundHandlePool>* i;
|
||||
for (i = getFirst(); i != NULL; i = i->getNext()) {
|
||||
Z2SoundHandlePool* handle = i->getObject();
|
||||
|
||||
@@ -502,7 +502,7 @@ void Z2SoundObjAnime::startSoundInner(const JGeometry::TVec3<f32>& 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 {
|
||||
|
||||
@@ -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},
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -24,6 +24,8 @@
|
||||
#include "m_Do/m_Do_graphic.h"
|
||||
#include <cstring>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
#include "m_Do/m_Do_Reset.h"
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
#include "dusk/string.hpp"
|
||||
#if TARGET_PC
|
||||
#include <format>
|
||||
#include <fmt/ranges.h>
|
||||
@@ -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;
|
||||
|
||||
@@ -17,6 +17,12 @@
|
||||
#include <memory>
|
||||
|
||||
#include "JSystem/JKernel/JKRHeap.h"
|
||||
#include "dusk/os.h"
|
||||
|
||||
#if _WIN32
|
||||
#define WIN32_LEAN_AND_MEAN 1
|
||||
#include <windows.h>
|
||||
#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
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
#include "Adpcm.hpp"
|
||||
|
||||
#include <cassert>
|
||||
#include <fstream>
|
||||
|
||||
#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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
#ifndef DUSK_ADPCM_HPP
|
||||
#define DUSK_ADPCM_HPP
|
||||
|
||||
#include <dolphin/types.h>
|
||||
|
||||
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
|
||||
@@ -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");
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
#include "dusk/audio/DuskAudioSystem.h"
|
||||
|
||||
#include <SDL3/SDL_init.h>
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <fstream>
|
||||
#include <ios>
|
||||
#include <span>
|
||||
|
||||
#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<f32, DSP_SUBFRAME_SIZE * OutputSubframe::NUM_CHANNELS> 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<JASChannel>::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<u16>(countSubframes) * DSP_SUBFRAME_SIZE;
|
||||
}
|
||||
|
||||
static void InterleaveOutputData(const OutputSubframe& data, std::span<f32> 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<f32>(value) / static_cast<f32>(JASDriver::getChannelLevel_dsp());
|
||||
}
|
||||
@@ -0,0 +1,497 @@
|
||||
#include <ar.h>
|
||||
#include <dolphin/os.h>
|
||||
|
||||
#include "DuskDsp.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <span>
|
||||
|
||||
#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<int>(static_cast<u64>(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<uintptr_t>(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<const BE(s16)*>(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<u8*>(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<int>(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<u32>(desiredSamples));
|
||||
|
||||
int renderSize = static_cast<int>(sizeof(s16) * renderSamples);
|
||||
auto renderData = static_cast<s16*>(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<int>(renderSize - skipSamples * sizeof(u16)));
|
||||
|
||||
assert(channel.mSamplePosition % channel.mSamplesPerBlock == 0 || channel.mSamplesLeft == 0);
|
||||
|
||||
return static_cast<int>(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<u32>(reinterpret_cast<uintptr_t>(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<f32>(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<f32> 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<void*>(static_cast<uintptr_t>(i)));
|
||||
}
|
||||
}
|
||||
|
||||
void dusk::audio::ApplyVolume(
|
||||
std::span<f32> dst,
|
||||
const std::span<f32> 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<f32>(src.size());
|
||||
auto curVolume = startVolume;
|
||||
for (int i = 0; i < src.size(); i++) {
|
||||
dst[i] = src[i] * curVolume;
|
||||
curVolume += step;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
#pragma once
|
||||
|
||||
#include "JSystem/JAudio2/JASDSPInterface.h"
|
||||
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
|
||||
#include "SDL3/SDL_audio.h"
|
||||
#include <span>
|
||||
|
||||
// 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<int>(OutputChannel::OutputChannel_MAX)];
|
||||
|
||||
f32& PrevVolume(OutputChannel channel) {
|
||||
assert(channel < OutputChannel::OutputChannel_MAX);
|
||||
return prevVolume[static_cast<int>(channel)];
|
||||
}
|
||||
};
|
||||
|
||||
extern ChannelAuxData ChannelAux[DSP_CHANNELS];
|
||||
|
||||
/**
|
||||
* Data storage for a single subframe and output channel's worth of samples.
|
||||
*/
|
||||
using DspSubframe = std::array<f32, DSP_SUBFRAME_SIZE>;
|
||||
|
||||
/**
|
||||
* Data storage for a single subframe's worth of samples, across all output channels.
|
||||
*/
|
||||
struct OutputSubframe {
|
||||
static constexpr int NUM_CHANNELS = static_cast<int>(OutputChannel::OutputChannel_MAX);
|
||||
|
||||
std::array<DspSubframe, NUM_CHANNELS> channels;
|
||||
|
||||
DspSubframe& operator[](OutputChannel channel) {
|
||||
assert(channel < OutputChannel::OutputChannel_MAX);
|
||||
return channels[static_cast<int>(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<f32> dst, std::span<f32> src, f32 startVolume, f32 endVolume);
|
||||
|
||||
extern f32 MasterVolume;
|
||||
extern f32 PrevMasterVolume;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
#include "JSystem/JAudio2/JASCriticalSection.h"
|
||||
|
||||
#include <mutex>
|
||||
|
||||
static std::recursive_mutex gAudioThreadMutex;
|
||||
|
||||
JASCriticalSection::JASCriticalSection() {
|
||||
gAudioThreadMutex.lock();
|
||||
}
|
||||
|
||||
JASCriticalSection::~JASCriticalSection() {
|
||||
gAudioThreadMutex.unlock();
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user