From 88d1cd404e4352531783e3c09ab53e86baa437a9 Mon Sep 17 00:00:00 2001 From: Phillip Stephens Date: Wed, 29 Nov 2023 22:51:46 -0800 Subject: [PATCH] MusyX: add missing files Former-commit-id: cb7c8e496e17429d4378927ae391fd8591de1c5f --- include/musyx/adsr.h | 64 ++++ include/musyx/dspvoice.h | 114 ++++++ include/musyx/macros.h | 26 ++ include/musyx/platform.h | 22 ++ include/musyx/s3d.h | 21 ++ include/musyx/sal.h | 81 ++++ include/musyx/snd.h | 30 ++ include/musyx/stream.h | 76 ++++ include/musyx/synthdata.h | 211 +++++++++++ include/musyx/voice.h | 258 +++++++++++++ src/musyx/runtime/dolphin/dsp_import.c | 428 +++++++++++++++++++++ src/musyx/runtime/dolphin/hardware.c | 504 +++++++++++++++++++++++++ src/musyx/runtime/dolphin/hw_aramdma.c | 339 +++++++++++++++++ src/musyx/runtime/dolphin/hw_dolphin.c | 171 +++++++++ src/musyx/runtime/dolphin/profile.c | 94 +++++ 15 files changed, 2439 insertions(+) create mode 100644 include/musyx/adsr.h create mode 100644 include/musyx/dspvoice.h create mode 100644 include/musyx/macros.h create mode 100644 include/musyx/platform.h create mode 100644 include/musyx/s3d.h create mode 100644 include/musyx/sal.h create mode 100644 include/musyx/snd.h create mode 100644 include/musyx/stream.h create mode 100644 include/musyx/synthdata.h create mode 100644 include/musyx/voice.h create mode 100644 src/musyx/runtime/dolphin/dsp_import.c create mode 100644 src/musyx/runtime/dolphin/hardware.c create mode 100644 src/musyx/runtime/dolphin/hw_aramdma.c create mode 100644 src/musyx/runtime/dolphin/hw_dolphin.c create mode 100644 src/musyx/runtime/dolphin/profile.c diff --git a/include/musyx/adsr.h b/include/musyx/adsr.h new file mode 100644 index 00000000..162b2dcd --- /dev/null +++ b/include/musyx/adsr.h @@ -0,0 +1,64 @@ +#ifndef ADSR_H +#define ADSR_H + +#include "musyx/musyx.h" +typedef struct ADSR_INFO { + // total size: 0x14 + union ai_data { + struct { + // total size: 0x14 + s32 atime; // offset 0x0, size 0x4 + s32 dtime; // offset 0x4, size 0x4 + u16 slevel; // offset 0x8, size 0x2 + u16 rtime; // offset 0xA, size 0x2 + s32 ascale; // offset 0xC, size 0x4 + s32 dscale; // offset 0x10, size 0x4 + } dls; + struct { + // total size: 0x8 + u16 atime; // offset 0x0, size 0x2 + u16 dtime; // offset 0x2, size 0x2 + u16 slevel; // offset 0x4, size 0x2 + u16 rtime; // offset 0x6, size 0x2 + } linear; + } data; // offset 0x0, size 0x14 +} ADSR_INFO; + +typedef struct ADSR_VARS { + u8 mode; + u8 state; + u32 cnt; + s32 currentVolume; + s32 currentIndex; + s32 currentDelta; + + union data { + struct _dls { + u32 aTime; + u32 dTime; + u16 sLevel; + u32 rTime; + u16 cutOff; + u8 aMode; + } dls; + + struct _linear { + u32 aTime; + u32 dTime; + u16 sLevel; + u32 rTime; + } linear; + } data; +} ADSR_VARS; + +#ifdef __cplusplus +extern "C" { +#endif +u32 adsrHandleLowPrecision(ADSR_VARS* adsr, u16* adsr_start, u16* adsr_delta); +bool adsrRelease(ADSR_VARS* adsr); + +#ifdef __cplusplus +} +#endif + +#endif // ADSR_H diff --git a/include/musyx/dspvoice.h b/include/musyx/dspvoice.h new file mode 100644 index 00000000..71790238 --- /dev/null +++ b/include/musyx/dspvoice.h @@ -0,0 +1,114 @@ +#ifndef DSPVOICE_H +#define DSPVOICE_H + +#include "musyx/musyx.h" + +#include "musyx/voice.h" +#include "musyx/synthdata.h" + +typedef struct DSPvoice { + _PB* pb; + void* patchData; + void* itdBuffer; + struct DSPvoice* next; + struct DSPvoice* prev; + struct DSPvoice* nextAlien; + u32 mesgCallBackUserValue; + u32 prio; + u32 currentAddr; + u32 changed[5]; + u32 pitch[5]; + u16 volL; + u16 volR; + u16 volS; + u16 volLa; + u16 volRa; + u16 volSa; + u16 volLb; + u16 volRb; + u16 volSb; + u16 lastVolL; + u16 lastVolR; + u16 lastVolS; + u16 lastVolLa; + u16 lastVolRa; + u16 lastVolSa; + u16 lastVolLb; + u16 lastVolRb; + u16 lastVolSb; + u16 smp_id; + SAMPLE_INFO smp_info; + VSampleInfo vSampleInfo; + u8 streamLoopPS; + ADSR_VARS adsr; + u16 srcTypeSelect; + u16 srcCoefSelect; + u16 itdShiftL; + u16 itdShiftR; + u8 singleOffset; + struct { + u32 posHi; + u32 posLo; + u32 pitch; + } playInfo; + + struct { + u8 pitch; + u8 vol; + u8 volA; + u8 volB; + } lastUpdate; + + u32 virtualSampleID; + u8 state; + u8 postBreak; + u8 startupBreak; + u8 studio; + u32 flags; +} DSPvoice; +typedef struct DSPhostDPop { + // total size: 0x24 + s32 l; // offset 0x0, size 0x4 + s32 r; // offset 0x4, size 0x4 + s32 s; // offset 0x8, size 0x4 + s32 lA; // offset 0xC, size 0x4 + s32 rA; // offset 0x10, size 0x4 + s32 sA; // offset 0x14, size 0x4 + s32 lB; // offset 0x18, size 0x4 + s32 rB; // offset 0x1C, size 0x4 + s32 sB; // offset 0x20, size 0x4 +} DSPhostDPop; + +typedef struct DSPinput { + // total size: 0xC + u8 studio; // offset 0x0, size 0x1 + u16 vol; // offset 0x2, size 0x2 + u16 volA; // offset 0x4, size 0x2 + u16 volB; // offset 0x6, size 0x2 + SND_STUDIO_INPUT* desc; // offset 0x8, size 0x4 +} DSPinput; + +typedef struct DSPstudioinfo { + // total size: 0xBC + _SPB* spb; // offset 0x0, size 0x4 + DSPhostDPop hostDPopSum; // offset 0x4, size 0x24 + s32* main[2]; // offset 0x28, size 0x8 + s32* auxA[3]; // offset 0x30, size 0xC + s32* auxB[3]; // offset 0x3C, size 0xC + DSPvoice* voiceRoot; // offset 0x48, size 0x4 + DSPvoice* alienVoiceRoot; // offset 0x4C, size 0x4 + u8 state; // offset 0x50, size 0x1 + u8 isMaster; // offset 0x51, size 0x1 + u8 numInputs; // offset 0x52, size 0x1 + SND_STUDIO_TYPE type; // offset 0x54, size 0x4 + DSPinput in[7]; // offset 0x58, size 0x54 + SND_AUX_CALLBACK auxAHandler; // offset 0xAC, size 0x4 + SND_AUX_CALLBACK auxBHandler; // offset 0xB0, size 0x4 + void* auxAUser; // offset 0xB4, size 0x4 + void* auxBUser; // offset 0xB8, size 0x4 +} DSPstudioinfo; + +extern DSPstudioinfo dspStudio[8]; +extern DSPvoice* dspVoice; + +#endif \ No newline at end of file diff --git a/include/musyx/macros.h b/include/musyx/macros.h new file mode 100644 index 00000000..c5bb2d68 --- /dev/null +++ b/include/musyx/macros.h @@ -0,0 +1,26 @@ +#ifndef _MUSYX_MACROS +#define _MUSYX_MACROS + +#include "musyx/musyx.h" +#include "musyx/synth.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void macInit(); +bool macPostMessage(SND_VOICEID vid, s32 mesg); +u32 macStart(u16 macid, u8 priority, u8 maxVoices, u16 allocId, u8 key, u8 vol, u8 panning, u8 midi, + u8 midiSet, u8 section, u16 step, u16 trackid, u8 new_vid, u8 vGroup, u8 studio, + u32 itd); +void macHandle(u32 deltaTime); +void macMakeInactive(SYNTH_VOICE* svoice, MAC_STATE); +void macSetPedalState(SYNTH_VOICE* svoice, u32 state); +void macSetExternalKeyoff(SYNTH_VOICE* svoice); +void macSampleEndNotify(SYNTH_VOICE* sv); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/include/musyx/platform.h b/include/musyx/platform.h new file mode 100644 index 00000000..9c327709 --- /dev/null +++ b/include/musyx/platform.h @@ -0,0 +1,22 @@ +#ifndef _MUSYX_PLATFORM +#define _MUSYX_PLATFORM + + +#define MUSY_TARGET_PC 0 +#define MUSY_TARGET_DOLPHIN 1 + +#ifndef MUSY_TARGET +#define MUSY_TARGET MUSY_TARGET_PC +#endif + +#ifndef ATTRIBUTE_ALIGN +#if defined(__MWERKS__) || defined(__GNUC__) +#define ATTRIBUTE_ALIGN(num) __attribute__((aligned(num))) +#elif defined(_MSC_VER) +#define ATTRIBUTE_ALIGN(num) +#else +#error unknown compiler +#endif +#endif + +#endif \ No newline at end of file diff --git a/include/musyx/s3d.h b/include/musyx/s3d.h new file mode 100644 index 00000000..ef9dde67 --- /dev/null +++ b/include/musyx/s3d.h @@ -0,0 +1,21 @@ +#ifndef _MUSYX_S3D +#define _MUSYX_S3D + +#include "musyx/musyx.h" + +#include "musyx/synthdata.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void s3dKillAllEmitter(); +void s3dInit(u32); /* extern */ +void s3dKillEmitterByFXID(FX_TAB* fxTab, u32 num); +void s3dExit(); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/include/musyx/sal.h b/include/musyx/sal.h new file mode 100644 index 00000000..e065b087 --- /dev/null +++ b/include/musyx/sal.h @@ -0,0 +1,81 @@ +#ifndef SAL_H +#define SAL_H + +#include "musyx/dspvoice.h" +#include "musyx/musyx.h" +typedef void (*SND_SOME_CALLBACK)(); + +#define CLAMP(value, min, max) ((value) > (max) ? (max) : (value) < (min) ? (min) : (value)) +// TODO matching hack +#define CLAMP_INV(value, min, max) ((value) < (min) ? (min) : (value) > (max) ? (max) : (value)) + +#ifdef __cplusplus +extern "C" { +#endif +typedef struct SAL_VOLINFO { + // total size: 0x24 + f32 volL; // offset 0x0, size 0x4 + f32 volR; // offset 0x4, size 0x4 + f32 volS; // offset 0x8, size 0x4 + f32 volAuxAL; // offset 0xC, size 0x4 + f32 volAuxAR; // offset 0x10, size 0x4 + f32 volAuxAS; // offset 0x14, size 0x4 + f32 volAuxBL; // offset 0x18, size 0x4 + f32 volAuxBR; // offset 0x1C, size 0x4 + f32 volAuxBS; // offset 0x20, size 0x4 +} SAL_VOLINFO; + +typedef struct SAL_PANINFO { + // total size: 0x30 + u32 pan_i; // offset 0x0, size 0x4 + u32 pan_im; // offset 0x4, size 0x4 + u32 span_i; // offset 0x8, size 0x4 + u32 span_im; // offset 0xC, size 0x4 + u32 rpan_i; // offset 0x10, size 0x4 + u32 rpan_im; // offset 0x14, size 0x4 + f32 pan_f; // offset 0x18, size 0x4 + f32 pan_fm; // offset 0x1C, size 0x4 + f32 span_f; // offset 0x20, size 0x4 + f32 span_fm; // offset 0x24, size 0x4 + f32 rpan_f; // offset 0x28, size 0x4 + f32 rpan_fm; // offset 0x2C, size 0x4 +} SAL_PANINFO; + +u32 salInitAi(SND_SOME_CALLBACK, u32, u32*); +u32 salInitDsp(u32); +u32 salInitDspCtrl(u8 numVoices, u8 numStudios, u32 defaultStudioDPL2); +u32 salStartAi(); +void salInitHRTFBuffer(); +void salActivateVoice(DSPvoice* dsp_vptr, u8 studio); +void salDeactivateVoice(DSPvoice* dsp_vptr); +void salActivateStudio(u8 studio, u32 isMaster, SND_STUDIO_TYPE type); +void salDeactivateStudio(u8 studio); +void salActivateVoice(DSPvoice* dsp_vptr, u8 studio); +void salCalcVolume(u8 voltab_index, SAL_VOLINFO* vi, f32 vol, u32 pan, u32 span, f32 auxa, f32 auxb, + u32 itd, u32 dpl2); +void salReconnectVoice(DSPvoice* dsp_vptr, u8 studio); +void* salMalloc(u32 len); +void salFree(void* addr); + +#define SAL_MAX_STUDIONUM 8 +extern u8 salMaxStudioNum; +extern u8 salNumVoices; + +void salApplyMatrix(const SND_FMATRIX* a, const SND_FVECTOR* b, SND_FVECTOR* out); +f32 salNormalizeVector(SND_FVECTOR* vec); +void salCrossProduct(SND_FVECTOR* out, const SND_FVECTOR* a, const SND_FVECTOR* b); + +#define SAL_CROSS_PRODUCT(out, a, b) \ + do { \ + out.x = (a.y * b.z) - (a.z * b.y); \ + out.y = (a.z * b.x) - (a.x * b.z); \ + out.z = (a.x * b.y) - (a.y * b.x); \ + } while (0) + +void salInvertMatrix(SND_FMATRIX* out, const SND_FMATRIX* in); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/musyx/snd.h b/include/musyx/snd.h new file mode 100644 index 00000000..b068a723 --- /dev/null +++ b/include/musyx/snd.h @@ -0,0 +1,30 @@ +#ifndef SND_H +#define SND_H + +#include "musyx/musyx.h" +#include "musyx/voice.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef s32 (*SND_COMPARE)(void*, void*); + +u16 sndRand(void); +s16 sndSin(u16 angle); +void* sndBSearch(void* key, void* base, s32 num, s32 len, SND_COMPARE cmp); +void sndConvertMs(u32* time); +void sndConvertTicks(u32* out, SYNTH_VOICE* svoice); +u32 sndConvert2Ms(u32 time); +u32 sndStreamAllocLength(u32 num, u32 flags); +void sndStreamFree(u32 stid); +u32 sndStreamActivate(u32 stid); +void sndStreamDeactivate(u32 stid); +u32 sndGetPitch(u8 key, u32 sInfo); +s32 sndPitchUpOne(u16 note); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/musyx/stream.h b/include/musyx/stream.h new file mode 100644 index 00000000..c2a5681c --- /dev/null +++ b/include/musyx/stream.h @@ -0,0 +1,76 @@ +#ifndef _MUSYX_STREAM +#define _MUSYX_STREAM + +#include "musyx/musyx.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef s32 (*SND_STREAM_UPDATE_CALLBACK)(void* buffer1, u32 len1, void* buffer2, u32 len2, + u32 user); +typedef struct SNDADPCMinfo { + // total size: 0x28 + u16 numCoef; // offset 0x0, size 0x2 + u8 initialPS; // offset 0x2, size 0x1 + u8 loopPS; // offset 0x3, size 0x1 + s16 loopY0; // offset 0x4, size 0x2 + s16 loopY1; // offset 0x6, size 0x2 + s16 coefTab[8][2]; // offset 0x8, size 0x20 +} SNDADPCMinfo; + +typedef struct STREAM_INFO { +#if MUSY_VERSION >= MUSY_VERSION_CHECK(1, 5, 4) + u32 nextStreamHandle; +#endif + u32 stid; + u32 flags; + u8 state; + u8 type; + /* These were moved to near the start of the structure in later versions */ +#if MUSY_VERSION >= MUSY_VERSION_CHECK(1, 5, 4) + u8 hwStreamHandle; + u8 lastPSFromBuffer; +#endif + SND_STREAM_UPDATE_CALLBACK updateFunction; + s16* buffer; + u32 size; + u32 bytes; + u32 last; + SNDADPCMinfo adpcmInfo; + volatile SND_VOICEID voice; + u32 user; + u32 frq; + u8 prio; + u8 vol; + u8 pan; + u8 span; + u8 auxa; + u8 auxb; + +#if MUSY_VERSION >= MUSY_VERSION_CHECK(1, 5, 4) + u8 orgPan; + u8 orgSPan; +#endif + + u8 studio; + /* These were moved to near the start of the structure in later versions */ +#if MUSY_VERSION <= MUSY_VERSION_CHECK(1, 5, 3) + u8 hwStreamHandle; + u32 nextStreamHandle; +#endif +} STREAM_INFO; + +#if MUSY_VERSION >= MUSY_VERSION_CHECK(1, 5, 4) +void streamOutputModeChanged(); +#endif + +void streamInit(); /* extern */ +void streamKill(SND_VOICEID voice); +void streamCorrectLoops(); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/include/musyx/synthdata.h b/include/musyx/synthdata.h new file mode 100644 index 00000000..d350fa2e --- /dev/null +++ b/include/musyx/synthdata.h @@ -0,0 +1,211 @@ +#ifndef SYNTHDATA_H +#define SYNTHDATA_H + +#include "musyx/macros.h" + +#ifdef __cplusplus +extern "C" { +#endif +typedef struct SAMPLE_INFO { + // total size: 0x20 + u32 info; // offset 0x0, size 0x4 + void* addr; // offset 0x4, size 0x4 + void* extraData; // offset 0x8, size 0x4 + u32 offset; // offset 0xC, size 0x4 + u32 length; // offset 0x10, size 0x4 + u32 loop; // offset 0x14, size 0x4 + u32 loopLength; // offset 0x18, size 0x4 + u8 compType; // offset 0x1C, size 0x1 +} SAMPLE_INFO; + +typedef struct GROUP_DATA { + // total size: 0x28 + u32 nextOff; // offset 0x0, size 0x4 + u16 id; // offset 0x4, size 0x2 + u16 type; // offset 0x6, size 0x2 + u32 macroOff; // offset 0x8, size 0x4 + u32 sampleOff; // offset 0xC, size 0x4 + u32 curveOff; // offset 0x10, size 0x4 + u32 keymapOff; // offset 0x14, size 0x4 + u32 layerOff; // offset 0x18, size 0x4 + union { + struct fx { + // total size: 0x4 + u32 tableOff; // offset 0x0, size 0x4 + } fx; + struct song { + // total size: 0xC + u32 normpageOff; // offset 0x0, size 0x4 + u32 drumpageOff; // offset 0x4, size 0x4 + u32 midiSetupOff; // offset 0x8, size 0x4 + } song; + } data; // offset 0x1C, size 0xC +} GROUP_DATA; + +typedef struct SAMPLE_HEADER { + // total size: 0x10 + u32 info; // offset 0x0, size 0x4 + u32 length; // offset 0x4, size 0x4 + u32 loopOffset; // offset 0x8, size 0x4 + u32 loopLength; // offset 0xC, size 0x4 +} SAMPLE_HEADER; + +typedef struct SDIR_DATA { + // total size: 0x20 + u16 id; // offset 0x0, size 0x2 + u16 ref_cnt; // offset 0x2, size 0x2 + u32 offset; // offset 0x4, size 0x4 + void* addr; // offset 0x8, size 0x4 + SAMPLE_HEADER header; // offset 0xC, size 0x10 + u32 extraData; // offset 0x1C, size 0x4 +} SDIR_DATA; + +typedef struct SDIR_TAB { + // total size: 0xC + SDIR_DATA* data; // offset 0x0, size 0x4 + void* base; // offset 0x4, size 0x4 + u16 numSmp; // offset 0x8, size 0x2 + u16 res; // offset 0xA, size 0x2 +} SDIR_TAB; + +typedef struct DATA_TAB { + // total size: 0x8 + void* data; // offset 0x0, size 0x4 + u16 id; // offset 0x4, size 0x2 + u16 refCount; // offset 0x6, size 0x2 +} DATA_TAB; + +typedef struct LAYER_TAB { + // total size: 0xC + void* data; // offset 0x0, size 0x4 + u16 id; // offset 0x4, size 0x2 + u16 num; // offset 0x6, size 0x2 + u16 refCount; // offset 0x8, size 0x2 + u16 reserved; // offset 0xA, size 0x2 +} LAYER_TAB; + +typedef struct MAC_MAINTAB { + // total size: 0x4 + u16 num; // offset 0x0, size 0x2 + u16 subTabIndex; // offset 0x2, size 0x2 +} MAC_MAINTAB; + +typedef struct MAC_SUBTAB { + // total size: 0x8 + void* data; // offset 0x0, size 0x4 + u16 id; // offset 0x4, size 0x2 + u16 refCount; // offset 0x6, size 0x2 +} MAC_SUBTAB; + +typedef struct GSTACK { + // total size: 0xC + GROUP_DATA* gAddr; // offset 0x0, size 0x4 + SDIR_DATA* sdirAddr; // offset 0x4, size 0x4 + void* prjAddr; // offset 0x8, size 0x4 +} GSTACK; + +typedef struct LAYER { + // total size: 0xC + u16 id; // offset 0x0, size 0x2 + u8 keyLow; // offset 0x2, size 0x1 + u8 keyHigh; // offset 0x3, size 0x1 + s8 transpose; // offset 0x4, size 0x1 + u8 volume; // offset 0x5, size 0x1 + s16 prioOffset; // offset 0x6, size 0x2 + u8 panning; // offset 0x8, size 0x1 + u8 reserved[3]; // offset 0x9, size 0x3 +} LAYER; + +typedef struct KEYMAP { + // total size: 0x8 + u16 id; // offset 0x0, size 0x2 + s8 transpose; // offset 0x2, size 0x1 + u8 panning; // offset 0x3, size 0x1 + s16 prioOffset; // offset 0x4, size 0x2 + u8 reserved[2]; // offset 0x6, size 0x2 +} KEYMAP; + +typedef struct MEM_DATA { + // total size: 0x408 + u32 nextOff; // offset 0x0, size 0x4 + u16 id; // offset 0x4, size 0x2 + u16 reserved; // offset 0x6, size 0x2 + union { + struct { + // total size: 0x10 + u32 num; // offset 0x0, size 0x4 + LAYER entry[1]; // offset 0x4, size 0xC + } layer; + KEYMAP map[128]; + u8 tab[1]; + MSTEP cmd[1][2]; + } data; // offset 0x8, size 0x400 +} MEM_DATA; + +typedef struct POOL_DATA { + // total size: 0x10 + u32 macroOff; // offset 0x0, size 0x4 + u32 curveOff; // offset 0x4, size 0x4 + u32 keymapOff; // offset 0x8, size 0x4 + u32 layerOff; // offset 0xC, size 0x4 +} POOL_DATA; + +typedef struct FX_TAB { + // total size: 0xA + u16 id; // offset 0x0, size 0x2 + u16 macro; // offset 0x2, size 0x2 + u8 maxVoices; // offset 0x4, size 0x1 + u8 priority; // offset 0x5, size 0x1 + u8 volume; // offset 0x6, size 0x1 + u8 panning; // offset 0x7, size 0x1 + u8 key; // offset 0x8, size 0x1 + u8 vGroup; // offset 0x9, size 0x1 +} FX_TAB; + +typedef struct FX_DATA { + // total size: 0xE + u16 num; // offset 0x0, size 0x2 + u16 reserverd; // offset 0x2, size 0x2 + FX_TAB fx[1]; // offset 0x4, size 0xA +} FX_DATA; + +typedef struct FX_GROUP { + // total size: 0x8 + u16 gid; // offset 0x0, size 0x2 + u16 fxNum; // offset 0x2, size 0x2 + FX_TAB* fxTab; // offset 0x4, size 0x4 +} FX_GROUP; + +void dataInit(u32, u32); /* extern */ +void dataExit(); +#if MUSY_VERSION >= MUSY_VERSION_CHECK(2, 0, 3) +void dataInitStack(unsigned long aramBase, unsigned long aramSize); +#else +void dataInitStack(); /* extern */ +#endif +u32 dataInsertSDir(SDIR_DATA* sdir, void* smp_data); +u32 dataRemoveSDir(SDIR_DATA* sdir); +u32 dataInsertMacro(u16 mid, void* macroaddr); +u32 dataRemoveMacro(u16 mid); +u32 dataInsertCurve(u16 cid, void* curvedata); +u32 dataRemoveCurve(u16 sid); +s32 dataGetSample(u16 sid, SAMPLE_INFO* newsmp); +void* dataGetCurve(u16 cid); +u32 dataAddSampleReference(u16 sid); +u32 dataRemoveSampleReference(u16 sid); +u32 dataInsertKeymap(u16 cid, void* keymapdata); +u32 dataRemoveKeymap(u16 sid); +u32 dataInsertLayer(u16 cid, void* layerdata, u16 size); +u32 dataRemoveLayer(u16 sid); +u32 dataInsertFX(u16 gid, FX_TAB* fx, u16 fxNum); +bool dataRemoveFX(u16 gid); +FX_TAB* dataGetFX(u16 fid); +void* dataGetLayer(u16 cid, u16* n); +void* dataGetKeymap(u16 cid); +MSTEP* dataGetMacro(u16 mid); + +#ifdef __cplusplus +} +#endif + +#endif // SYNTHDATA_H diff --git a/include/musyx/voice.h b/include/musyx/voice.h new file mode 100644 index 00000000..ce195c1a --- /dev/null +++ b/include/musyx/voice.h @@ -0,0 +1,258 @@ +#ifndef _MUSYX_VOICE_H_ +#define _MUSYX_VOICE_H_ + +#include "musyx/synth.h" +#include "musyx/version.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct _PBMIX { + // total size: 0x24 + u16 vL; // offset 0x0, size 0x2 + u16 vDeltaL; // offset 0x2, size 0x2 + u16 vR; // offset 0x4, size 0x2 + u16 vDeltaR; // offset 0x6, size 0x2 + u16 vAuxAL; // offset 0x8, size 0x2 + u16 vDeltaAuxAL; // offset 0xA, size 0x2 + u16 vAuxAR; // offset 0xC, size 0x2 + u16 vDeltaAuxAR; // offset 0xE, size 0x2 + u16 vAuxBL; // offset 0x10, size 0x2 + u16 vDeltaAuxBL; // offset 0x12, size 0x2 + u16 vAuxBR; // offset 0x14, size 0x2 + u16 vDeltaAuxBR; // offset 0x16, size 0x2 + u16 vAuxBS; // offset 0x18, size 0x2 + u16 vDeltaAuxBS; // offset 0x1A, size 0x2 + u16 vS; // offset 0x1C, size 0x2 + u16 vDeltaS; // offset 0x1E, size 0x2 + u16 vAuxAS; // offset 0x20, size 0x2 + u16 vDeltaAuxAS; // offset 0x22, size 0x2 +} _PBMIX; + +typedef struct _PBITD { + // total size: 0xE + u16 flag; // offset 0x0, size 0x2 + u16 bufferHi; // offset 0x2, size 0x2 + u16 bufferLo; // offset 0x4, size 0x2 + u16 shiftL; // offset 0x6, size 0x2 + u16 shiftR; // offset 0x8, size 0x2 + u16 targetShiftL; // offset 0xA, size 0x2 + u16 targetShiftR; // offset 0xC, size 0x2 +} _PBITD; + +typedef struct _PBUPDATE { + // total size: 0xE + u16 updNum[5]; // offset 0x0, size 0xA + u16 dataHi; // offset 0xA, size 0x2 + u16 dataLo; // offset 0xC, size 0x2 +} _PBUPDATE; + +typedef struct _PBDPOP { + // total size: 0x12 + u16 aL; // offset 0x0, size 0x2 + u16 aAuxAL; // offset 0x2, size 0x2 + u16 aAuxBL; // offset 0x4, size 0x2 + u16 aR; // offset 0x6, size 0x2 + u16 aAuxAR; // offset 0x8, size 0x2 + u16 aAuxBR; // offset 0xA, size 0x2 + u16 aS; // offset 0xC, size 0x2 + u16 aAuxAS; // offset 0xE, size 0x2 + u16 aAuxBS; // offset 0x10, size 0x2 +} _PBDPOP; + +typedef struct _PBVE { + // total size: 0x4 + u16 currentVolume; // offset 0x0, size 0x2 + u16 currentDelta; // offset 0x2, size 0x2 +} _PBVE; + +typedef struct _PBFIR { + // total size: 0x6 + u16 numCoefs; // offset 0x0, size 0x2 + u16 coefsHi; // offset 0x2, size 0x2 + u16 coefsLo; // offset 0x4, size 0x2 +} _PBFIR; + +typedef struct _PBADDR { + // total size: 0x10 + u16 loopFlag; // offset 0x0, size 0x2 + u16 format; // offset 0x2, size 0x2 + u16 loopAddressHi; // offset 0x4, size 0x2 + u16 loopAddressLo; // offset 0x6, size 0x2 + u16 endAddressHi; // offset 0x8, size 0x2 + u16 endAddressLo; // offset 0xA, size 0x2 + u16 currentAddressHi; // offset 0xC, size 0x2 + u16 currentAddressLo; // offset 0xE, size 0x2 +} _PBADDR; + +typedef struct _PBADPCM { + // total size: 0x28 + u16 a[8][2]; // offset 0x0, size 0x20 + u16 gain; // offset 0x20, size 0x2 + u16 pred_scale; // offset 0x22, size 0x2 + u16 yn1; // offset 0x24, size 0x2 + u16 yn2; // offset 0x26, size 0x2 +} _PBADPCM; + +typedef struct _PBSRC { + // total size: 0xE + u16 ratioHi; // offset 0x0, size 0x2 + u16 ratioLo; // offset 0x2, size 0x2 + u16 currentAddressFrac; // offset 0x4, size 0x2 + u16 last_samples[4]; // offset 0x6, size 0x8 +} _PBSRC; + +typedef struct _PBADPCMLOOP { + // total size: 0x6 + u16 loop_pred_scale; // offset 0x0, size 0x2 + u16 loop_yn1; // offset 0x2, size 0x2 + u16 loop_yn2; // offset 0x4, size 0x2 +} _PBADPCMLOOP; + +typedef struct _PB { + // total size: 0xBC + u16 nextHi; // offset 0x0, size 0x2 + u16 nextLo; // offset 0x2, size 0x2 + u16 currHi; // offset 0x4, size 0x2 + u16 currLo; // offset 0x6, size 0x2 + u16 srcSelect; // offset 0x8, size 0x2 + u16 coefSelect; // offset 0xA, size 0x2 + u16 mixerCtrl; // offset 0xC, size 0x2 + u16 state; // offset 0xE, size 0x2 + u16 loopType; // offset 0x10, size 0x2 + _PBMIX mix; // offset 0x12, size 0x24 + _PBITD itd; // offset 0x36, size 0xE + _PBUPDATE update; // offset 0x44, size 0xE + _PBDPOP dpop; // offset 0x52, size 0x12 + _PBVE ve; // offset 0x64, size 0x4 + _PBFIR fir; // offset 0x68, size 0x6 + _PBADDR addr; // offset 0x6E, size 0x10 + _PBADPCM adpcm; // offset 0x7E, size 0x28 + _PBSRC src; // offset 0xA6, size 0xE + _PBADPCMLOOP adpcmLoop; // offset 0xB4, size 0x6 + u16 streamLoopCnt; // offset 0xBA, size 0x2 +} _PB; + +typedef struct VSampleInfo { + // total size: 0xC + void* loopBufferAddr; // offset 0x0, size 0x4 + u32 loopBufferLength; // offset 0x4, size 0x4 + u8 inLoopBuffer; // offset 0x8, size 0x1 +} VSampleInfo; + +typedef struct SND_VIRTUALSAMPLE_INFO { + // total size: 0x14 + u16 smpID; // offset 0x0, size 0x2 + u16 instID; // offset 0x2, size 0x2 + union vsData { + struct vsUpdate { + // total size: 0x10 + u32 off1; // offset 0x0, size 0x4 + u32 len1; // offset 0x4, size 0x4 + u32 off2; // offset 0x8, size 0x4 + u32 len2; // offset 0xC, size 0x4 + } update; + } data; +} SND_VIRTUALSAMPLE_INFO; + +typedef struct VS_BUFFER { + // total size: 0x24 + u8 state; // offset 0x0, size 0x1 + u8 hwId; // offset 0x1, size 0x1 + u8 smpType; // offset 0x2, size 0x1 + u8 voice; // offset 0x3, size 0x1 + u32 last; // offset 0x4, size 0x4 + u32 finalGoodSamples; // offset 0x8, size 0x4 + u32 finalLast; // offset 0xC, size 0x4 + SND_VIRTUALSAMPLE_INFO info; // offset 0x10, size 0x14 +} VS_BUFFER; + +typedef struct _VS { + // total size: 0x950 + u8 numBuffers; // offset 0x0, size 0x1 + u32 bufferLength; // offset 0x4, size 0x4 + VS_BUFFER streamBuffer[64]; // offset 0x8, size 0x900 + u8 voices[64]; // offset 0x908, size 0x40 + u16 nextInstID; // offset 0x948, size 0x2 + u32 (*callback)(u8, + SND_VIRTUALSAMPLE_INFO*); // offset 0x94C, size 0x4 +} VS; + +extern VS vs; + +typedef struct _SPB { + // total size: 0x36 + u16 dpopLHi; // offset 0x0, size 0x2 + u16 dpopLLo; // offset 0x2, size 0x2 + u16 dpopLDelta; // offset 0x4, size 0x2 + u16 dpopRHi; // offset 0x6, size 0x2 + u16 dpopRLo; // offset 0x8, size 0x2 + u16 dpopRDelta; // offset 0xA, size 0x2 + u16 dpopSHi; // offset 0xC, size 0x2 + u16 dpopSLo; // offset 0xE, size 0x2 + u16 dpopSDelta; // offset 0x10, size 0x2 + u16 dpopALHi; // offset 0x12, size 0x2 + u16 dpopALLo; // offset 0x14, size 0x2 + u16 dpopALDelta; // offset 0x16, size 0x2 + u16 dpopARHi; // offset 0x18, size 0x2 + u16 dpopARLo; // offset 0x1A, size 0x2 + u16 dpopARDelta; // offset 0x1C, size 0x2 + u16 dpopASHi; // offset 0x1E, size 0x2 + u16 dpopASLo; // offset 0x20, size 0x2 + u16 dpopASDelta; // offset 0x22, size 0x2 + u16 dpopBLHi; // offset 0x24, size 0x2 + u16 dpopBLLo; // offset 0x26, size 0x2 + u16 dpopBLDelta; // offset 0x28, size 0x2 + u16 dpopBRHi; // offset 0x2A, size 0x2 + u16 dpopBRLo; // offset 0x2C, size 0x2 + u16 dpopBRDelta; // offset 0x2E, size 0x2 + u16 dpopBSHi; // offset 0x30, size 0x2 + u16 dpopBSLo; // offset 0x32, size 0x2 + u16 dpopBSDelta; // offset 0x34, size 0x2 +} _SPB; + +extern u16 voicePrioSortRootListRoot; +extern u8 voiceMusicRunning; +extern u8 voiceFxRunning; +extern u8 voiceListInsert; +extern u8 voiceListRoot; + +void vsInit(); /* extern */ +u32 vsSampleStartNotify(u8 voice); +void vsSampleEndNotify(u32 pubID); + +void voiceSetPriority(SYNTH_VOICE* svoice, u8 prio); +u32 voiceIsLastStarted(SYNTH_VOICE* svoice); +void voiceSetLastStarted(SYNTH_VOICE* svoice); +void voiceResetLastStarted(SYNTH_VOICE* svoice); +void voiceInitLastStarted(); +s32 voiceKillSound(u32 voiceid); +void voiceKill(u32 vi); +void voiceSetPriority(SYNTH_VOICE* svoice, u8 prio); +u32 voiceIsLastStarted(SYNTH_VOICE* svoice); +void voiceSetLastStarted(SYNTH_VOICE* svoice); +void voiceResetLastStarted(SYNTH_VOICE* svoice); +void voiceInitLastStarted(); +s32 voiceKillSound(u32 voiceid); +void voiceKill(u32 vi); +u32 voiceBlock(u8 prio); +u32 voiceAllocate(u8 priority, u8 maxVoices, u16 allocId, u8 fxFlag); +#if MUSY_VERSION >= MUSY_VERSION_CHECK(2, 0, 3) +int voiceAllocatePeek(u8 priority, u8 maxVoices, u32 allocId, u8 fxFlag, u32* currentAllocId); +#endif + +void voiceFree(SYNTH_VOICE* svoice); +void voiceUnblock(u32 voice); +void voiceRemovePriority(SYNTH_VOICE* svoice); + +void vidInit(); +u32 vidGetInternalId(SND_VOICEID id); +void vidRemoveVoiceReferences(SYNTH_VOICE* svoice); +u32 vidMakeNew(SYNTH_VOICE* svoice, u32 isMaster); +u32 vidMakeRoot(SYNTH_VOICE* svoice); + +#ifdef __cplusplus +} +#endif +#endif \ No newline at end of file diff --git a/src/musyx/runtime/dolphin/dsp_import.c b/src/musyx/runtime/dolphin/dsp_import.c new file mode 100644 index 00000000..4b5573a6 --- /dev/null +++ b/src/musyx/runtime/dolphin/dsp_import.c @@ -0,0 +1,428 @@ +#include "musyx/dsp_import.h" + +#ifdef __cplusplus +extern "C" { +#endif + +char dspSlave[0x19E0] ATTRIBUTE_ALIGN(32) = { + 0x00, 0x00, 0x00, 0x00, 0x02, 0x9F, 0x0C, 0x10, 0x02, 0x9F, 0x0C, 0x1F, 0x02, 0x9F, 0x0C, 0x3B, + 0x02, 0x9F, 0x0C, 0x4A, 0x02, 0x9F, 0x0C, 0x50, 0x02, 0x9F, 0x0C, 0x82, 0x02, 0x9F, 0x0C, 0x88, + 0x13, 0x02, 0x13, 0x03, 0x12, 0x04, 0x13, 0x05, 0x13, 0x06, 0x8E, 0x00, 0x8C, 0x00, 0x8B, 0x00, + 0x00, 0x92, 0x00, 0xFF, 0x81, 0x00, 0x89, 0x00, 0x00, 0x9E, 0x0E, 0x80, 0x00, 0xFE, 0x0E, 0x1B, + 0x81, 0x00, 0x00, 0xFE, 0x0E, 0x31, 0x16, 0xFC, 0xDC, 0xD1, 0x16, 0xFD, 0x00, 0x00, 0x16, 0xFB, + 0x00, 0x01, 0x26, 0xFC, 0x02, 0xA0, 0x80, 0x00, 0x02, 0x9C, 0x00, 0x29, 0x02, 0x9F, 0x00, 0x45, + 0x13, 0x02, 0x13, 0x03, 0x12, 0x04, 0x13, 0x05, 0x13, 0x06, 0x8E, 0x00, 0x8C, 0x00, 0x8B, 0x00, + 0x00, 0x92, 0x00, 0xFF, 0x16, 0xFC, 0xDC, 0xD1, 0x16, 0xFD, 0x00, 0x01, 0x16, 0xFB, 0x00, 0x01, + 0x26, 0xFC, 0x02, 0xA0, 0x80, 0x00, 0x02, 0x9C, 0x00, 0x40, 0x8E, 0x00, 0x81, 0x00, 0x89, 0x00, + 0x00, 0x9F, 0xBA, 0xBE, 0x26, 0xFE, 0x02, 0xC0, 0x80, 0x00, 0x02, 0x9C, 0x00, 0x4A, 0x82, 0x00, + 0x02, 0x94, 0x00, 0x4A, 0x23, 0xFF, 0x81, 0x00, 0x26, 0xFE, 0x02, 0xC0, 0x80, 0x00, 0x02, 0x9C, + 0x00, 0x54, 0x27, 0xFF, 0x02, 0x40, 0x7F, 0xFF, 0x2E, 0xCE, 0x2F, 0xCF, 0x16, 0xCD, 0x0C, 0x00, + 0x81, 0x00, 0x2E, 0xC9, 0x1F, 0xFB, 0x2F, 0xCB, 0x02, 0xBF, 0x05, 0x5C, 0x00, 0x80, 0x0C, 0x00, + 0x8E, 0x00, 0x81, 0x00, 0x89, 0x70, 0xB1, 0x00, 0x02, 0x91, 0x00, 0x7E, 0x0A, 0x12, 0xC1, 0x00, + 0x02, 0x92, 0x00, 0x7E, 0x00, 0x9F, 0x0A, 0xFF, 0x4C, 0x00, 0x1C, 0x7E, 0x02, 0x13, 0x1C, 0x7E, + 0x17, 0x6F, 0x16, 0xFC, 0xFB, 0xAD, 0x16, 0xFD, 0x80, 0x80, 0x00, 0x21, 0x16, 0xFC, 0xBA, 0xAD, + 0x2E, 0xFD, 0x00, 0x21, 0x81, 0x00, 0x89, 0x70, 0x8E, 0x78, 0x2E, 0xCE, 0x2F, 0xCF, 0x00, 0x9E, + 0x0E, 0x44, 0x2E, 0xCD, 0x0E, 0x00, 0x2E, 0xC9, 0x00, 0x9E, 0x00, 0x40, 0x2E, 0xCB, 0x00, 0x81, + 0x0E, 0x44, 0x00, 0x82, 0x00, 0x00, 0x00, 0x9B, 0x00, 0x9F, 0x00, 0x9A, 0x01, 0x40, 0x81, 0x00, + 0x89, 0x00, 0x8F, 0x00, 0x02, 0xBF, 0x05, 0x5C, 0x19, 0x3E, 0x19, 0x3C, 0xB1, 0x00, 0x19, 0x3F, + 0x02, 0x94, 0x00, 0xA6, 0x00, 0x5A, 0x1B, 0x5E, 0x02, 0x9F, 0x00, 0xAE, 0x99, 0x00, 0x1B, 0x5E, + 0x1B, 0x5C, 0x00, 0x7B, 0x00, 0xAD, 0x4C, 0x00, 0x1B, 0x5E, 0x1B, 0x5C, 0x19, 0x3E, 0x19, 0x3C, + 0xB1, 0x00, 0x19, 0x3F, 0x02, 0x94, 0x00, 0xB8, 0x00, 0x5A, 0x1B, 0x5E, 0x02, 0x9F, 0x00, 0xC0, + 0x99, 0x00, 0x1B, 0x5E, 0x1B, 0x5C, 0x00, 0x7B, 0x00, 0xBF, 0x4C, 0x00, 0x1B, 0x5E, 0x1B, 0x5C, + 0x19, 0x3E, 0x19, 0x3C, 0xB1, 0x00, 0x19, 0x3F, 0x02, 0x94, 0x00, 0xCA, 0x00, 0x5A, 0x1B, 0x5E, + 0x02, 0x9F, 0x00, 0xD2, 0x99, 0x00, 0x1B, 0x5E, 0x1B, 0x5C, 0x00, 0x7B, 0x00, 0xD1, 0x4C, 0x00, + 0x1B, 0x5E, 0x1B, 0x5C, 0x00, 0x82, 0x04, 0x00, 0x19, 0x3E, 0x19, 0x3C, 0xB1, 0x79, 0x02, 0x94, + 0x00, 0xDD, 0x00, 0x5A, 0x1B, 0x5E, 0x02, 0x9F, 0x00, 0xE5, 0x99, 0x00, 0x1B, 0x5E, 0x1B, 0x5C, + 0x00, 0x7B, 0x00, 0xE4, 0x4C, 0x00, 0x1B, 0x5E, 0x1B, 0x5C, 0x19, 0x3E, 0x19, 0x3C, 0xB1, 0x79, + 0x02, 0x94, 0x00, 0xEE, 0x00, 0x5A, 0x1B, 0x5E, 0x02, 0x9F, 0x00, 0xF6, 0x99, 0x00, 0x1B, 0x5E, + 0x1B, 0x5C, 0x00, 0x7B, 0x00, 0xF5, 0x4C, 0x00, 0x1B, 0x5E, 0x1B, 0x5C, 0x19, 0x3E, 0x19, 0x3C, + 0xB1, 0x79, 0x02, 0x94, 0x00, 0xFF, 0x00, 0x5A, 0x1B, 0x5E, 0x02, 0x9F, 0x01, 0x07, 0x99, 0x00, + 0x1B, 0x5E, 0x1B, 0x5C, 0x00, 0x7B, 0x01, 0x06, 0x4C, 0x00, 0x1B, 0x5E, 0x1B, 0x5C, 0x00, 0x82, + 0x07, 0xC0, 0x19, 0x3E, 0x19, 0x3C, 0xB1, 0x79, 0x02, 0x94, 0x01, 0x12, 0x00, 0x5A, 0x1B, 0x5E, + 0x02, 0x9F, 0x01, 0x1A, 0x99, 0x00, 0x1B, 0x5E, 0x1B, 0x5C, 0x00, 0x7B, 0x01, 0x19, 0x4C, 0x00, + 0x1B, 0x5E, 0x1B, 0x5C, 0x19, 0x3E, 0x19, 0x3C, 0xB1, 0x79, 0x02, 0x94, 0x01, 0x23, 0x00, 0x5A, + 0x1B, 0x5E, 0x02, 0x9F, 0x01, 0x2B, 0x99, 0x00, 0x1B, 0x5E, 0x1B, 0x5C, 0x00, 0x7B, 0x01, 0x2A, + 0x4C, 0x00, 0x1B, 0x5E, 0x1B, 0x5C, 0x19, 0x3E, 0x19, 0x3C, 0xB1, 0x79, 0x02, 0x94, 0x01, 0x34, + 0x00, 0x5A, 0x1B, 0x5E, 0x02, 0x9F, 0x01, 0x3C, 0x99, 0x00, 0x1B, 0x5E, 0x1B, 0x5C, 0x00, 0x7B, + 0x01, 0x3B, 0x4C, 0x00, 0x1B, 0x5E, 0x1B, 0x5C, 0x02, 0x9F, 0x00, 0x68, 0x00, 0x85, 0xFF, 0xFF, + 0x81, 0x50, 0x89, 0x40, 0x8E, 0x48, 0x00, 0xFA, 0x0E, 0x17, 0x00, 0xF8, 0x0E, 0x18, 0x00, 0x81, + 0x00, 0x00, 0x02, 0xBF, 0x04, 0xF1, 0x00, 0xDA, 0x0E, 0x17, 0x00, 0xD8, 0x0E, 0x18, 0x89, 0x48, + 0x00, 0x81, 0x04, 0x00, 0x02, 0xBF, 0x04, 0xF1, 0x00, 0xDA, 0x0E, 0x17, 0x00, 0xD8, 0x0E, 0x18, + 0x89, 0x48, 0x00, 0x81, 0x07, 0xC0, 0x02, 0xBF, 0x04, 0xF1, 0x02, 0x9F, 0x00, 0x68, 0x00, 0x86, + 0x07, 0xC0, 0x02, 0xBF, 0x04, 0x84, 0x02, 0x9F, 0x00, 0x68, 0x81, 0x00, 0x8E, 0x00, 0x19, 0x1E, + 0x19, 0x1C, 0x2E, 0xCE, 0x2C, 0xCF, 0x16, 0xCD, 0x00, 0x00, 0x16, 0xC9, 0x00, 0x01, 0x16, 0xCB, + 0x07, 0x80, 0x02, 0xBF, 0x05, 0x5C, 0x02, 0x9F, 0x00, 0x68, 0x81, 0x00, 0x89, 0x70, 0x8E, 0x60, + 0x2E, 0xCE, 0x2C, 0xCF, 0x16, 0xCD, 0x0E, 0x44, 0x16, 0xC9, 0x00, 0x00, 0x89, 0x00, 0x0D, 0x20, + 0x2D, 0xCB, 0x4C, 0x00, 0x1C, 0x80, 0x00, 0x80, 0x02, 0x80, 0x00, 0x81, 0x00, 0x00, 0x00, 0x82, + 0x01, 0x40, 0x00, 0x83, 0x0E, 0x44, 0x0A, 0x00, 0x27, 0xC9, 0x03, 0xA0, 0x00, 0x04, 0x02, 0x9C, + 0x01, 0x8C, 0x2E, 0xCE, 0x2C, 0xCF, 0x16, 0xCD, 0x0E, 0x54, 0x16, 0xC9, 0x00, 0x00, 0x16, 0xCB, + 0x02, 0x60, 0x00, 0x9F, 0x00, 0xA0, 0x8F, 0x00, 0x00, 0x7F, 0x01, 0xA5, 0x19, 0x7E, 0x1B, 0x1A, + 0x19, 0x7C, 0x1B, 0x1A, 0x1B, 0x5E, 0x7C, 0x22, 0x1B, 0x3E, 0x1B, 0x3C, 0x1C, 0x04, 0x02, 0x9F, + 0x00, 0x68, 0x8E, 0x70, 0x89, 0x60, 0x19, 0x1F, 0x2E, 0xCE, 0x2C, 0xCF, 0x16, 0xCD, 0x0C, 0x00, + 0x16, 0xC9, 0x00, 0x00, 0x05, 0x03, 0x03, 0x40, 0xFF, 0xF0, 0x2F, 0xCB, 0x02, 0xBF, 0x05, 0x5C, + 0x00, 0x80, 0x0C, 0x00, 0x02, 0x9F, 0x00, 0x68, 0x81, 0x00, 0x89, 0x70, 0x8E, 0x78, 0x2E, 0xCE, + 0x2F, 0xCF, 0x16, 0xCD, 0x0B, 0x80, 0x16, 0xC9, 0x00, 0x00, 0x16, 0xCB, 0x00, 0xC0, 0x00, 0x82, + 0x0E, 0x08, 0x00, 0x9F, 0x00, 0x00, 0x1B, 0x5F, 0x00, 0x9F, 0x01, 0x40, 0x1B, 0x5F, 0x00, 0x9F, + 0x02, 0x80, 0x1B, 0x5F, 0x00, 0x9F, 0x04, 0x00, 0x1B, 0x5F, 0x00, 0x9F, 0x05, 0x40, 0x1B, 0x5F, + 0x00, 0x9F, 0x06, 0x80, 0x1B, 0x5F, 0x00, 0x9F, 0x07, 0xC0, 0x1B, 0x5F, 0x00, 0x9F, 0x09, 0x00, + 0x1B, 0x5F, 0x00, 0x9F, 0x0A, 0x40, 0x1B, 0x5F, 0x02, 0xBF, 0x05, 0x5C, 0x00, 0xDE, 0x0B, 0xA7, + 0x00, 0xDF, 0x0B, 0xA8, 0x2E, 0xCE, 0x2F, 0xCF, 0x16, 0xCD, 0x03, 0xC0, 0x16, 0xC9, 0x00, 0x00, + 0x16, 0xCB, 0x00, 0x80, 0x81, 0x00, 0x89, 0x00, 0x00, 0xDE, 0x0B, 0x84, 0x00, 0x9F, 0x0B, 0x31, + 0x4C, 0x00, 0x1C, 0x7E, 0x02, 0x13, 0x00, 0xFE, 0x0E, 0x15, 0x00, 0xDE, 0x0B, 0x85, 0x00, 0x9F, + 0x0B, 0x34, 0x4C, 0x00, 0x1C, 0x7E, 0x02, 0x13, 0x00, 0xFE, 0x0E, 0x16, 0x00, 0xDE, 0x0B, 0x86, + 0x00, 0x9F, 0x0B, 0x11, 0x4C, 0x00, 0x1C, 0x7E, 0x02, 0x13, 0x00, 0xFE, 0x0E, 0x14, 0x81, 0x00, + 0x00, 0xDE, 0x0B, 0x9B, 0xB1, 0x00, 0x02, 0x95, 0x02, 0x3A, 0x89, 0x00, 0x00, 0xDF, 0x0B, 0x9E, + 0x03, 0x00, 0x0C, 0xC0, 0x00, 0xFF, 0x0E, 0x40, 0x00, 0xDF, 0x0B, 0x9F, 0x03, 0x00, 0x0C, 0xC0, + 0x00, 0xFF, 0x0E, 0x41, 0x00, 0x9F, 0x0C, 0xE0, 0x00, 0xFF, 0x0E, 0x42, 0x00, 0xFF, 0x0E, 0x43, + 0x02, 0xBF, 0x05, 0x5C, 0x00, 0xDE, 0x0B, 0x9C, 0x2E, 0xCE, 0x00, 0xDE, 0x0B, 0x9D, 0x2E, 0xCF, + 0x16, 0xCD, 0x0C, 0xC0, 0x16, 0xC9, 0x00, 0x00, 0x16, 0xCB, 0x00, 0x40, 0x02, 0xBF, 0x05, 0x5C, + 0x02, 0x9F, 0x00, 0x68, 0x00, 0x9F, 0x0C, 0xE0, 0x00, 0xFF, 0x0E, 0x42, 0x00, 0xFF, 0x0E, 0x40, + 0x00, 0xFF, 0x0E, 0x41, 0x00, 0xFF, 0x0E, 0x43, 0x02, 0xBF, 0x05, 0x5C, 0x02, 0x9F, 0x00, 0x68, + 0x8E, 0x00, 0x00, 0xE0, 0x0E, 0x07, 0x00, 0x80, 0x0B, 0xA2, 0x00, 0x81, 0x03, 0xC0, 0x0E, 0x05, + 0x00, 0xFE, 0x0E, 0x04, 0x89, 0x00, 0x81, 0x50, 0x00, 0x9F, 0x0B, 0x80, 0x00, 0x7A, 0x02, 0x5B, + 0x19, 0x3E, 0x4C, 0x49, 0x1C, 0x5E, 0x1A, 0x59, 0x00, 0x83, 0x0E, 0x05, 0x1B, 0x61, 0x1B, 0x60, + 0x00, 0xDE, 0x0B, 0x87, 0x06, 0x01, 0x02, 0x95, 0x02, 0x67, 0x02, 0x9F, 0x03, 0x32, 0x00, 0xDE, + 0x0E, 0x42, 0x00, 0xFE, 0x0E, 0x1C, 0x00, 0xC3, 0x0E, 0x15, 0x17, 0x7F, 0x8E, 0x00, 0x8A, 0x00, + 0x81, 0x00, 0x89, 0x00, 0x00, 0xDE, 0x0B, 0xB3, 0x00, 0xDF, 0x0B, 0xB2, 0x1F, 0x1F, 0x4D, 0x00, + 0x14, 0x81, 0x8D, 0x1E, 0x1F, 0xD8, 0x00, 0x98, 0x80, 0x00, 0x00, 0x80, 0x0E, 0x44, 0xA8, 0x30, + 0xAC, 0x38, 0xAD, 0x30, 0xAC, 0x38, 0xAD, 0x30, 0xAC, 0x38, 0xAD, 0x30, 0xAC, 0x38, 0xAD, 0x30, + 0xAC, 0x38, 0xAD, 0x30, 0xAC, 0x38, 0xAD, 0x30, 0xAC, 0x38, 0xAD, 0x30, 0xAC, 0x38, 0xAD, 0x30, + 0xAC, 0x38, 0xAD, 0x30, 0xAC, 0x38, 0xAD, 0x30, 0xAC, 0x38, 0xAD, 0x30, 0xAC, 0x38, 0xAD, 0x30, + 0xAC, 0x38, 0xAD, 0x30, 0xAC, 0x38, 0xAD, 0x30, 0xAC, 0x38, 0xAD, 0x30, 0xAC, 0x38, 0x00, 0xFE, + 0x0B, 0xB2, 0x8F, 0x00, 0x00, 0x80, 0x0E, 0x44, 0x00, 0xC1, 0x0E, 0x43, 0x1C, 0x61, 0x19, 0x3A, + 0x19, 0x18, 0x90, 0x59, 0x19, 0x19, 0x9E, 0x51, 0x80, 0x80, 0x97, 0x59, 0x80, 0x91, 0x9E, 0x51, + 0x80, 0x80, 0x97, 0x59, 0x80, 0x91, 0x9E, 0x51, 0x80, 0x80, 0x97, 0x59, 0x80, 0x91, 0x9E, 0x51, + 0x80, 0x80, 0x97, 0x59, 0x80, 0x91, 0x9E, 0x51, 0x80, 0x80, 0x97, 0x59, 0x80, 0x91, 0x9E, 0x51, + 0x80, 0x80, 0x97, 0x59, 0x80, 0x91, 0x9E, 0x51, 0x80, 0x80, 0x97, 0x59, 0x80, 0x91, 0x9E, 0x51, + 0x80, 0x80, 0x97, 0x59, 0x80, 0x91, 0x9E, 0x51, 0x80, 0x80, 0x97, 0x59, 0x80, 0x91, 0x9E, 0x51, + 0x80, 0x80, 0x97, 0x59, 0x80, 0x91, 0x9E, 0x51, 0x80, 0x80, 0x97, 0x59, 0x80, 0x91, 0x9E, 0x51, + 0x80, 0x80, 0x97, 0x59, 0x80, 0x91, 0x9E, 0x51, 0x80, 0x80, 0x97, 0x59, 0x80, 0x91, 0x9E, 0x51, + 0x80, 0x80, 0x97, 0x59, 0x80, 0x91, 0x9E, 0x51, 0x80, 0x80, 0x97, 0x59, 0x80, 0x91, 0x9E, 0x00, + 0x6F, 0x33, 0x1B, 0x7F, 0x00, 0xC3, 0x0E, 0x14, 0x8F, 0x00, 0x8D, 0x00, 0x8A, 0x00, 0x17, 0x7F, + 0x81, 0x00, 0x00, 0xDE, 0x0B, 0x9B, 0xB1, 0x00, 0x02, 0x95, 0x03, 0x2A, 0x00, 0xDE, 0x0E, 0x42, + 0x00, 0xFE, 0x0E, 0x43, 0x81, 0x00, 0x89, 0x00, 0x00, 0xDE, 0x0B, 0x9E, 0x00, 0xDF, 0x0B, 0xA0, + 0x82, 0x00, 0x02, 0x93, 0x03, 0x06, 0x78, 0x00, 0x02, 0x9F, 0x03, 0x09, 0x02, 0x95, 0x03, 0x09, + 0x74, 0x00, 0x00, 0xFE, 0x0B, 0x9E, 0x00, 0xDF, 0x0E, 0x43, 0x05, 0xE0, 0x4C, 0x00, 0x00, 0xFE, + 0x0E, 0x40, 0x81, 0x00, 0x89, 0x00, 0x00, 0xDE, 0x0B, 0x9F, 0x00, 0xDF, 0x0B, 0xA1, 0x82, 0x00, + 0x02, 0x93, 0x03, 0x1D, 0x78, 0x00, 0x02, 0x9F, 0x03, 0x20, 0x02, 0x95, 0x03, 0x20, 0x74, 0x00, + 0x00, 0xFE, 0x0B, 0x9F, 0x00, 0xDF, 0x0E, 0x43, 0x05, 0xE0, 0x4C, 0x00, 0x00, 0xFE, 0x0E, 0x41, + 0x02, 0x9F, 0x03, 0x32, 0x00, 0xDE, 0x0E, 0x42, 0x00, 0xFE, 0x0E, 0x40, 0x00, 0xFE, 0x0E, 0x41, + 0x00, 0xFE, 0x0E, 0x43, 0x81, 0x00, 0x8E, 0x00, 0x84, 0x00, 0x89, 0x00, 0x1E, 0xFE, 0x0E, 0x40, + 0x1E, 0xBE, 0x00, 0x83, 0x0E, 0x08, 0x1C, 0x03, 0x1F, 0xF5, 0x19, 0x1A, 0xF8, 0x58, 0xFB, 0xA0, + 0xF8, 0xB1, 0xFB, 0xA0, 0xF8, 0xB1, 0xFB, 0xA0, 0xF8, 0xB1, 0xFB, 0xA0, 0xF8, 0x3B, 0x1B, 0x7E, + 0x00, 0x83, 0x0E, 0x04, 0x81, 0x00, 0x89, 0x73, 0x19, 0x61, 0x19, 0x60, 0x78, 0x00, 0x00, 0xFE, + 0x0E, 0x04, 0x02, 0x94, 0x02, 0x53, 0x8E, 0x00, 0x81, 0x00, 0x00, 0xDE, 0x0B, 0x9B, 0xB1, 0x00, + 0x02, 0x95, 0x03, 0x6A, 0x00, 0xDE, 0x0B, 0x9C, 0x00, 0xDC, 0x0B, 0x9D, 0x2E, 0xCE, 0x2C, 0xCF, + 0x81, 0x00, 0x00, 0xDE, 0x0E, 0x1C, 0x2E, 0xCD, 0x16, 0xC9, 0x00, 0x01, 0x16, 0xCB, 0x00, 0x40, + 0x02, 0xBF, 0x05, 0x5C, 0x81, 0x00, 0x89, 0x00, 0x00, 0xDE, 0x0B, 0x82, 0x00, 0xDF, 0x0B, 0x83, + 0x2E, 0xCE, 0x2F, 0xCF, 0x16, 0xCD, 0x0B, 0x80, 0x16, 0xC9, 0x00, 0x01, 0x16, 0xCB, 0x00, 0xC0, + 0x02, 0xBF, 0x05, 0x5C, 0x81, 0x00, 0x00, 0xDE, 0x0B, 0x80, 0x00, 0xDC, 0x0B, 0x81, 0xB1, 0x00, + 0x02, 0x94, 0x03, 0x86, 0x00, 0xC0, 0x0E, 0x07, 0x02, 0x9F, 0x00, 0x68, 0x2E, 0xCE, 0x2C, 0xCF, + 0x16, 0xCD, 0x0B, 0x80, 0x16, 0xC9, 0x00, 0x00, 0x16, 0xCB, 0x00, 0xC0, 0x00, 0x82, 0x0E, 0x08, + 0x00, 0x9F, 0x00, 0x00, 0x1B, 0x5F, 0x00, 0x9F, 0x01, 0x40, 0x1B, 0x5F, 0x00, 0x9F, 0x02, 0x80, + 0x1B, 0x5F, 0x00, 0x9F, 0x04, 0x00, 0x1B, 0x5F, 0x00, 0x9F, 0x05, 0x40, 0x1B, 0x5F, 0x00, 0x9F, + 0x06, 0x80, 0x1B, 0x5F, 0x00, 0x9F, 0x07, 0xC0, 0x1B, 0x5F, 0x00, 0x9F, 0x09, 0x00, 0x1B, 0x5F, + 0x00, 0x9F, 0x0A, 0x40, 0x1B, 0x5F, 0x02, 0xBF, 0x05, 0x5C, 0x00, 0xDE, 0x0B, 0xA7, 0x00, 0xDF, + 0x0B, 0xA8, 0x2E, 0xCE, 0x2F, 0xCF, 0x16, 0xCD, 0x03, 0xC0, 0x16, 0xC9, 0x00, 0x00, 0x16, 0xCB, + 0x00, 0x80, 0x81, 0x00, 0x89, 0x00, 0x00, 0xDE, 0x0B, 0x84, 0x00, 0x9F, 0x0B, 0x31, 0x4C, 0x00, + 0x1C, 0x7E, 0x02, 0x13, 0x00, 0xFE, 0x0E, 0x15, 0x00, 0xDE, 0x0B, 0x85, 0x00, 0x9F, 0x0B, 0x34, + 0x4C, 0x00, 0x1C, 0x7E, 0x02, 0x13, 0x00, 0xFE, 0x0E, 0x16, 0x00, 0xDE, 0x0B, 0x86, 0x00, 0x9F, + 0x0B, 0x11, 0x4C, 0x00, 0x1C, 0x7E, 0x02, 0x13, 0x00, 0xFE, 0x0E, 0x14, 0x81, 0x00, 0x00, 0xDE, + 0x0B, 0x9B, 0xB1, 0x00, 0x02, 0x95, 0x04, 0x03, 0x89, 0x00, 0x00, 0xDF, 0x0B, 0x9E, 0x03, 0x00, + 0x0C, 0xC0, 0x00, 0xFF, 0x0E, 0x40, 0x00, 0xDF, 0x0B, 0x9F, 0x03, 0x00, 0x0C, 0xC0, 0x00, 0xFF, + 0x0E, 0x41, 0x00, 0x9F, 0x0C, 0xE0, 0x00, 0xFF, 0x0E, 0x42, 0x00, 0xFF, 0x0E, 0x43, 0x02, 0xBF, + 0x05, 0x5C, 0x00, 0xDE, 0x0B, 0x9C, 0x2E, 0xCE, 0x00, 0xDE, 0x0B, 0x9D, 0x2E, 0xCF, 0x16, 0xCD, + 0x0C, 0xC0, 0x16, 0xC9, 0x00, 0x00, 0x16, 0xCB, 0x00, 0x40, 0x02, 0xBF, 0x05, 0x5C, 0x00, 0xC0, + 0x0E, 0x07, 0x02, 0x9F, 0x02, 0x48, 0x00, 0x9F, 0x0C, 0xE0, 0x00, 0xFF, 0x0E, 0x42, 0x00, 0xFF, + 0x0E, 0x40, 0x00, 0xFF, 0x0E, 0x41, 0x00, 0xFF, 0x0E, 0x43, 0x02, 0xBF, 0x05, 0x5C, 0x00, 0xC0, + 0x0E, 0x07, 0x02, 0x9F, 0x02, 0x48, 0x8E, 0x00, 0x00, 0x86, 0x04, 0x00, 0x81, 0x00, 0x89, 0x70, + 0x19, 0x1C, 0x2E, 0xCE, 0x2C, 0xCF, 0x1F, 0xC6, 0x2E, 0xCD, 0x16, 0xC9, 0x00, 0x01, 0x16, 0xCB, + 0x07, 0x80, 0x02, 0xBF, 0x05, 0x5C, 0x02, 0xBF, 0x04, 0x84, 0x02, 0x9F, 0x00, 0x68, 0x8E, 0x00, + 0x00, 0x86, 0x07, 0xC0, 0x81, 0x00, 0x89, 0x70, 0x19, 0x1C, 0x2E, 0xCE, 0x2C, 0xCF, 0x1F, 0xC6, + 0x2E, 0xCD, 0x16, 0xC9, 0x00, 0x01, 0x16, 0xCB, 0x07, 0x80, 0x02, 0xBF, 0x05, 0x5C, 0x02, 0xBF, + 0x04, 0x84, 0x02, 0x9F, 0x00, 0x68, 0x8C, 0x00, 0x8A, 0x00, 0x81, 0x00, 0x89, 0x70, 0x19, 0x1F, + 0x2E, 0xCE, 0x2F, 0xCF, 0x16, 0xCD, 0x02, 0x80, 0x16, 0xC9, 0x00, 0x01, 0x16, 0xCB, 0x02, 0x80, + 0x8F, 0x50, 0x81, 0x40, 0x00, 0x81, 0x04, 0x00, 0x00, 0x83, 0x00, 0x00, 0x00, 0x82, 0x01, 0x40, + 0x00, 0x99, 0x00, 0x80, 0x02, 0xBF, 0x05, 0x5C, 0x11, 0x05, 0x04, 0x6C, 0x1F, 0x61, 0x11, 0x20, + 0x04, 0x5E, 0x89, 0x72, 0x19, 0x5C, 0xF0, 0x7B, 0x19, 0x7D, 0xF1, 0x31, 0x81, 0x39, 0x89, 0x00, + 0x68, 0x00, 0x2E, 0xCE, 0x2C, 0xCF, 0x1F, 0xFB, 0x2F, 0xCD, 0x0F, 0x01, 0x2F, 0xC9, 0x1F, 0xF9, + 0x2F, 0xCB, 0x72, 0x00, 0x1F, 0x5E, 0x1F, 0x1C, 0x81, 0x00, 0x26, 0xC9, 0x02, 0xA0, 0x00, 0x04, + 0x02, 0x9C, 0x04, 0x6D, 0x02, 0x9F, 0x00, 0x68, 0x02, 0x9F, 0x00, 0x68, 0x02, 0x9F, 0x00, 0x68, + 0x02, 0x9F, 0x00, 0x68, 0x16, 0xFC, 0xDC, 0xD1, 0x16, 0xFD, 0x00, 0x02, 0x16, 0xFB, 0x00, 0x01, + 0x02, 0x9F, 0x0C, 0x91, 0x02, 0x9F, 0x00, 0x45, 0x8E, 0x00, 0x19, 0x1F, 0x19, 0x1D, 0x1F, 0x5F, + 0x1F, 0x1D, 0x2F, 0xCE, 0x2D, 0xCF, 0x89, 0x00, 0x1F, 0xA6, 0x2D, 0xCD, 0x0E, 0x00, 0x2E, 0xC9, + 0x81, 0x00, 0x00, 0x9C, 0x00, 0xC0, 0x2C, 0xCB, 0x1C, 0xA0, 0x00, 0x81, 0x0E, 0x44, 0x48, 0x00, + 0x1B, 0x3E, 0x1B, 0x3C, 0x0B, 0x00, 0x00, 0x99, 0x00, 0x60, 0x4B, 0x00, 0x1B, 0x3D, 0x00, 0x81, + 0x0E, 0x44, 0x1C, 0x06, 0x00, 0x83, 0x00, 0x00, 0x1C, 0x43, 0x27, 0xC9, 0x03, 0xA0, 0x00, 0x04, + 0x02, 0x9C, 0x04, 0xA5, 0x11, 0x09, 0x04, 0xDA, 0x8E, 0x00, 0x19, 0x3A, 0x19, 0x38, 0x69, 0x00, + 0x2F, 0xCE, 0x2D, 0xCF, 0x89, 0x00, 0x19, 0x3D, 0x2D, 0xCD, 0x16, 0xC9, 0x00, 0x00, 0x81, 0x00, + 0x00, 0x9C, 0x00, 0xC0, 0x2C, 0xCB, 0x00, 0x81, 0x0E, 0x44, 0x48, 0x00, 0x1B, 0x3E, 0x1B, 0x3C, + 0x0B, 0x00, 0x09, 0x60, 0x4B, 0x00, 0x1B, 0x3D, 0x00, 0x81, 0x0E, 0x44, 0x8F, 0x00, 0x80, 0xF0, + 0x80, 0xC0, 0x6A, 0x00, 0x48, 0x00, 0x11, 0x17, 0x04, 0xD4, 0x80, 0xF0, 0x80, 0xC0, 0x6B, 0x32, + 0x49, 0x22, 0x80, 0xF0, 0x80, 0xC0, 0x6A, 0x3A, 0x48, 0x2A, 0x80, 0xF0, 0x80, 0xC0, 0x6B, 0x32, + 0x49, 0x22, 0x1B, 0x5F, 0x1B, 0x5D, 0x80, 0xF0, 0x80, 0xC0, 0x6A, 0x00, 0x48, 0x00, 0x11, 0x17, + 0x04, 0xE8, 0x80, 0xF0, 0x80, 0xC0, 0x6B, 0x32, 0x49, 0x22, 0x80, 0xF0, 0x80, 0xC0, 0x6A, 0x3A, + 0x48, 0x2A, 0x80, 0xF0, 0x80, 0xC0, 0x6B, 0x32, 0x49, 0x22, 0x1B, 0x5F, 0x1B, 0x5D, 0x1C, 0x05, + 0x02, 0xDF, 0x8E, 0x00, 0x00, 0x9B, 0x0E, 0x44, 0x00, 0x9D, 0x00, 0xC0, 0x02, 0xBF, 0x05, 0x41, + 0x49, 0x00, 0x00, 0xFF, 0x0E, 0x1D, 0x00, 0xFD, 0x0E, 0x1E, 0x89, 0x00, 0x02, 0xBF, 0x05, 0x5C, + 0x11, 0x04, 0x05, 0x2C, 0x00, 0xDA, 0x0E, 0x1D, 0x00, 0xD8, 0x0E, 0x1E, 0x00, 0x9B, 0x0E, 0xA4, + 0x00, 0x9D, 0x00, 0xC0, 0x02, 0xBF, 0x05, 0x41, 0x49, 0x00, 0x00, 0xFF, 0x0E, 0x1D, 0x00, 0xFD, + 0x0E, 0x1E, 0x00, 0x83, 0x0E, 0x44, 0x02, 0xBF, 0x05, 0x4C, 0x89, 0x00, 0x00, 0xDA, 0x0E, 0x1D, + 0x00, 0xD8, 0x0E, 0x1E, 0x00, 0x9B, 0x0E, 0x44, 0x00, 0x9D, 0x00, 0xC0, 0x02, 0xBF, 0x05, 0x41, + 0x49, 0x00, 0x00, 0xFF, 0x0E, 0x1D, 0x00, 0xFD, 0x0E, 0x1E, 0x00, 0x83, 0x0E, 0xA4, 0x02, 0xBF, + 0x05, 0x4C, 0x00, 0x00, 0x00, 0x00, 0x8E, 0x00, 0x89, 0x00, 0x00, 0xDA, 0x0E, 0x1D, 0x00, 0xD8, + 0x0E, 0x1E, 0x00, 0x9B, 0x0E, 0xA4, 0x00, 0x9D, 0x00, 0xC0, 0x02, 0xBF, 0x05, 0x41, 0x49, 0x00, + 0x00, 0x83, 0x0E, 0x44, 0x02, 0xBF, 0x05, 0x4C, 0x00, 0x83, 0x0E, 0xA4, 0x02, 0xBF, 0x05, 0x4C, + 0x02, 0xDF, 0x8E, 0x00, 0x00, 0xFA, 0xFF, 0xCE, 0x00, 0xF8, 0xFF, 0xCF, 0x00, 0xFB, 0xFF, 0xCD, + 0x16, 0xC9, 0x00, 0x00, 0x2D, 0xCB, 0x02, 0xDF, 0x8F, 0x00, 0x8D, 0x00, 0x8A, 0x00, 0x19, 0x7A, + 0x19, 0x78, 0xA0, 0x00, 0xB6, 0x00, 0x11, 0x30, 0x05, 0x5A, 0x91, 0x79, 0x4E, 0x6D, 0x19, 0x7A, + 0x4D, 0x43, 0xA0, 0x39, 0xB6, 0x29, 0x02, 0xDF, 0x26, 0xC9, 0x02, 0xA0, 0x00, 0x04, 0x02, 0x9C, + 0x05, 0x5C, 0x02, 0xDF, 0x26, 0xFE, 0x02, 0xC0, 0x80, 0x00, 0x02, 0x9C, 0x05, 0x62, 0x02, 0xDF, + 0x26, 0xFC, 0x02, 0xA0, 0x80, 0x00, 0x02, 0x9C, 0x05, 0x68, 0x02, 0xDF, 0x26, 0xFC, 0x02, 0xA0, + 0x80, 0x00, 0x02, 0x9C, 0x05, 0x6E, 0x02, 0xDF, 0x81, 0x00, 0x89, 0x70, 0x8E, 0x60, 0x2E, 0xCE, + 0x2C, 0xCF, 0x16, 0xCD, 0x0E, 0x44, 0x16, 0xC9, 0x00, 0x00, 0x89, 0x00, 0x0D, 0x20, 0x2D, 0xCB, + 0x4C, 0x00, 0x1C, 0x80, 0x00, 0x80, 0x02, 0x80, 0x00, 0x81, 0x00, 0x00, 0x00, 0x82, 0x01, 0x40, + 0x00, 0x83, 0x0E, 0x44, 0x0A, 0x00, 0x27, 0xC9, 0x03, 0xA0, 0x00, 0x04, 0x02, 0x9C, 0x05, 0x8B, + 0x2E, 0xCE, 0x2C, 0xCF, 0x16, 0xCD, 0x0E, 0x54, 0x16, 0xC9, 0x00, 0x00, 0x16, 0xCB, 0x02, 0x60, + 0x00, 0x9F, 0x00, 0xA0, 0x8F, 0x00, 0x00, 0x7F, 0x05, 0xA4, 0x19, 0x7E, 0x1B, 0x1A, 0x19, 0x7C, + 0x1B, 0x1A, 0x1B, 0x5E, 0x1B, 0x5C, 0x1B, 0x3E, 0x1B, 0x3C, 0x1C, 0x04, 0x02, 0x9F, 0x00, 0x68, + 0x00, 0x82, 0x0B, 0xB8, 0x19, 0x5E, 0x2E, 0xD1, 0x19, 0x5E, 0x2E, 0xD4, 0x19, 0x5E, 0x2E, 0xD5, + 0x19, 0x5E, 0x2E, 0xD6, 0x19, 0x5E, 0x2E, 0xD7, 0x19, 0x5E, 0x2E, 0xD8, 0x19, 0x5E, 0x2E, 0xD9, + 0x19, 0x5E, 0x2E, 0xA0, 0x19, 0x5E, 0x2E, 0xA1, 0x19, 0x5E, 0x2E, 0xA2, 0x19, 0x5E, 0x2E, 0xA3, + 0x19, 0x5E, 0x2E, 0xA4, 0x19, 0x5E, 0x2E, 0xA5, 0x19, 0x5E, 0x2E, 0xA6, 0x19, 0x5E, 0x2E, 0xA7, + 0x19, 0x5E, 0x2E, 0xA8, 0x19, 0x5E, 0x2E, 0xA9, 0x19, 0x5E, 0x2E, 0xAA, 0x19, 0x5E, 0x2E, 0xAB, + 0x19, 0x5E, 0x2E, 0xAC, 0x19, 0x5E, 0x2E, 0xAD, 0x19, 0x5E, 0x2E, 0xAE, 0x19, 0x5E, 0x2E, 0xAF, + 0x19, 0x5E, 0x2E, 0xDE, 0x19, 0x5E, 0x2E, 0xDA, 0x19, 0x5E, 0x2E, 0xDB, 0x19, 0x5E, 0x2E, 0xDC, + 0x8C, 0x00, 0x8A, 0x00, 0x8E, 0x00, 0x00, 0xD8, 0x0E, 0x16, 0x19, 0x5B, 0x19, 0x59, 0x81, 0x00, + 0x19, 0x5C, 0x00, 0x80, 0x0E, 0x44, 0x19, 0x5F, 0x1B, 0x1F, 0x19, 0x5F, 0x1B, 0x1F, 0x19, 0x5F, + 0x1B, 0x1F, 0x18, 0x5F, 0x1B, 0x1F, 0x6B, 0x00, 0x15, 0x05, 0x4D, 0x00, 0x15, 0x7E, 0x1C, 0x9F, + 0x1C, 0xBD, 0x05, 0xE0, 0x99, 0x00, 0x7D, 0x00, 0x1C, 0xDD, 0x89, 0x00, 0x1F, 0xA5, 0x15, 0x02, + 0x1C, 0xBF, 0x00, 0x9A, 0x01, 0xFC, 0x00, 0x9E, 0x0E, 0x44, 0x00, 0x81, 0xFF, 0xDD, 0x00, 0x83, + 0x0D, 0x80, 0x00, 0x64, 0x06, 0x1A, 0x18, 0x27, 0x1B, 0x07, 0x4A, 0x00, 0x1F, 0xFC, 0x18, 0x27, + 0x1B, 0x07, 0x15, 0x79, 0x35, 0x00, 0x18, 0x27, 0x1B, 0x07, 0x41, 0x00, 0x1B, 0x7E, 0x18, 0x27, + 0x1B, 0x07, 0x1B, 0x7F, 0x00, 0x00, 0x00, 0x65, 0x06, 0x20, 0x18, 0x27, 0x1B, 0x07, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x07, 0x18, 0x7F, 0x00, 0x66, 0x06, 0x29, 0x4A, 0x3B, 0x1F, 0xFC, 0x15, 0x79, + 0x35, 0x33, 0x41, 0x00, 0x1B, 0x7F, 0x00, 0x04, 0x18, 0x9F, 0x1A, 0xDF, 0x18, 0x9F, 0x1A, 0xDF, + 0x18, 0x9F, 0x1A, 0xDF, 0x18, 0x9F, 0x1A, 0xDF, 0x1A, 0xDC, 0x00, 0x82, 0x0B, 0xD2, 0x27, 0xDC, + 0x1A, 0xDF, 0x27, 0xDB, 0x1A, 0xDF, 0x27, 0xDA, 0x1A, 0xDF, 0x00, 0x82, 0x0B, 0xBE, 0x27, 0xD9, + 0x1A, 0xDF, 0x27, 0xD8, 0x1A, 0xDF, 0x8F, 0x00, 0x00, 0xC1, 0x0E, 0x42, 0x00, 0x82, 0x0D, 0x80, + 0x19, 0x40, 0x19, 0x43, 0x80, 0xF0, 0xB8, 0xC0, 0x11, 0x1F, 0x06, 0x54, 0xA6, 0xF0, 0xBC, 0xF0, + 0x19, 0x40, 0x19, 0x43, 0xBC, 0xF0, 0x4E, 0xC0, 0xB8, 0x31, 0xA6, 0xF0, 0xBC, 0xF0, 0xBC, 0x00, + 0x4E, 0x00, 0x1B, 0x3E, 0x00, 0xE1, 0x0E, 0x42, 0x02, 0xDF, 0x00, 0x82, 0x0B, 0xB8, 0x19, 0x5E, + 0x2E, 0xD1, 0x19, 0x5E, 0x2E, 0xD4, 0x19, 0x5E, 0x2E, 0xD5, 0x19, 0x5E, 0x2E, 0xD6, 0x19, 0x5E, + 0x2E, 0xD7, 0x19, 0x5E, 0x2E, 0xD8, 0x19, 0x5E, 0x2E, 0xD9, 0x19, 0x5E, 0x2E, 0xA0, 0x19, 0x5E, + 0x2E, 0xA1, 0x19, 0x5E, 0x2E, 0xA2, 0x19, 0x5E, 0x2E, 0xA3, 0x19, 0x5E, 0x2E, 0xA4, 0x19, 0x5E, + 0x2E, 0xA5, 0x19, 0x5E, 0x2E, 0xA6, 0x19, 0x5E, 0x2E, 0xA7, 0x19, 0x5E, 0x2E, 0xA8, 0x19, 0x5E, + 0x2E, 0xA9, 0x19, 0x5E, 0x2E, 0xAA, 0x19, 0x5E, 0x2E, 0xAB, 0x19, 0x5E, 0x2E, 0xAC, 0x19, 0x5E, + 0x2E, 0xAD, 0x19, 0x5E, 0x2E, 0xAE, 0x19, 0x5E, 0x2E, 0xAF, 0x19, 0x5E, 0x2E, 0xDE, 0x19, 0x5E, + 0x2E, 0xDA, 0x19, 0x5E, 0x2E, 0xDB, 0x19, 0x5E, 0x2E, 0xDC, 0x8C, 0x00, 0x8A, 0x00, 0x8E, 0x00, + 0x19, 0x5B, 0x19, 0x59, 0x81, 0x00, 0x19, 0x5C, 0x00, 0x80, 0x0E, 0x44, 0x19, 0x5F, 0x19, 0x5F, + 0x19, 0x5F, 0x1B, 0x1F, 0x18, 0x5F, 0x1B, 0x1F, 0x6B, 0x00, 0x15, 0x05, 0x4D, 0x00, 0x15, 0x7E, + 0x1C, 0x9F, 0x1C, 0xBD, 0x05, 0xE0, 0x99, 0x00, 0x7D, 0x00, 0x1C, 0xDD, 0x89, 0x00, 0x1F, 0xA5, + 0x15, 0x02, 0x1C, 0xBF, 0x00, 0x9A, 0x01, 0xFC, 0x00, 0x9E, 0x0E, 0x45, 0x00, 0x81, 0xFF, 0xDD, + 0x00, 0x83, 0x0D, 0x80, 0x00, 0x64, 0x06, 0xCB, 0x18, 0x27, 0x1B, 0x07, 0x4A, 0x00, 0x1B, 0x7E, + 0x18, 0x27, 0x1B, 0x07, 0x1B, 0x7C, 0x00, 0x00, 0x18, 0x27, 0x1B, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x27, 0x1B, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65, 0x06, 0xD1, 0x18, 0x27, 0x1B, 0x07, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x06, 0xD6, 0x4A, 0x00, 0x1B, 0x7E, 0x1B, 0x7C, 0x00, 0x04, + 0x18, 0x9F, 0x1A, 0xDF, 0x18, 0x9F, 0x1A, 0xDF, 0x18, 0x9F, 0x1A, 0xDF, 0x18, 0x9F, 0x1A, 0xDF, + 0x1A, 0xDC, 0x00, 0x82, 0x0B, 0xD2, 0x27, 0xDC, 0x1A, 0xDF, 0x27, 0xDB, 0x1A, 0xDF, 0x27, 0xDA, + 0x1A, 0xDF, 0x00, 0x82, 0x0B, 0xBE, 0x27, 0xD9, 0x1A, 0xDF, 0x27, 0xD8, 0x1A, 0xDF, 0x8D, 0x00, + 0x8B, 0x00, 0x8F, 0x00, 0x00, 0xC1, 0x0E, 0x42, 0x00, 0x82, 0x0D, 0x80, 0x81, 0x00, 0x11, 0x20, + 0x07, 0x03, 0x89, 0x00, 0x19, 0x40, 0x18, 0x9E, 0x18, 0x1B, 0x19, 0x9A, 0x54, 0x00, 0x1F, 0x5E, + 0x19, 0x59, 0xB0, 0x00, 0xFB, 0x00, 0x81, 0x39, 0x00, 0xE1, 0x0E, 0x42, 0x02, 0xDF, 0x00, 0x82, + 0x0B, 0xB8, 0x19, 0x5E, 0x2E, 0xD1, 0x19, 0x5E, 0x2E, 0xD4, 0x19, 0x5E, 0x2E, 0xD5, 0x19, 0x5E, + 0x2E, 0xD6, 0x19, 0x5E, 0x2E, 0xD7, 0x19, 0x5E, 0x2E, 0xD8, 0x19, 0x5E, 0x2E, 0xD9, 0x19, 0x5E, + 0x2E, 0xA0, 0x19, 0x5E, 0x2E, 0xA1, 0x19, 0x5E, 0x2E, 0xA2, 0x19, 0x5E, 0x2E, 0xA3, 0x19, 0x5E, + 0x2E, 0xA4, 0x19, 0x5E, 0x2E, 0xA5, 0x19, 0x5E, 0x2E, 0xA6, 0x19, 0x5E, 0x2E, 0xA7, 0x19, 0x5E, + 0x2E, 0xA8, 0x19, 0x5E, 0x2E, 0xA9, 0x19, 0x5E, 0x2E, 0xAA, 0x19, 0x5E, 0x2E, 0xAB, 0x19, 0x5E, + 0x2E, 0xAC, 0x19, 0x5E, 0x2E, 0xAD, 0x19, 0x5E, 0x2E, 0xAE, 0x19, 0x5E, 0x2E, 0xAF, 0x19, 0x5E, + 0x2E, 0xDE, 0x19, 0x5E, 0x2E, 0xDA, 0x19, 0x5E, 0x2E, 0xDB, 0x19, 0x5E, 0x2E, 0xDC, 0x00, 0xC0, + 0x0E, 0x42, 0x00, 0x81, 0xFF, 0xDD, 0x11, 0x20, 0x07, 0x48, 0x18, 0x24, 0x1B, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xE0, 0x0E, 0x42, 0x00, 0x82, 0x0B, 0xD9, 0x00, 0x04, 0x18, 0x9F, 0x1A, 0xDF, + 0x18, 0x9F, 0x1A, 0xDF, 0x18, 0x9F, 0x1A, 0xDF, 0x18, 0x9F, 0x1A, 0xDF, 0x89, 0x00, 0x1A, 0xDC, + 0x27, 0xDC, 0x00, 0xFF, 0x0B, 0xD2, 0x27, 0xDB, 0x00, 0xFF, 0x0B, 0xD1, 0x27, 0xDA, 0x00, 0xFF, + 0x0B, 0xD0, 0x27, 0xD9, 0x00, 0xFF, 0x0B, 0xBE, 0x27, 0xD8, 0x00, 0xFF, 0x0B, 0xBD, 0x02, 0xDF, + 0x00, 0xC0, 0x0E, 0x40, 0x00, 0x81, 0x0B, 0x89, 0x00, 0xC2, 0x0E, 0x08, 0x1C, 0x62, 0x00, 0xC4, + 0x0E, 0x41, 0x00, 0xC5, 0x0E, 0x09, 0x02, 0xBF, 0x80, 0xE7, 0x00, 0xF8, 0x0B, 0xA9, 0x00, 0xFB, + 0x0B, 0xAC, 0x02, 0xDF, 0x00, 0xC0, 0x0E, 0x40, 0x00, 0x81, 0x0B, 0x89, 0x00, 0xC2, 0x0E, 0x08, + 0x1C, 0x62, 0x00, 0xC4, 0x0E, 0x41, 0x00, 0xC5, 0x0E, 0x09, 0x02, 0xBF, 0x80, 0xE7, 0x00, 0xF8, + 0x0B, 0xA9, 0x00, 0xFB, 0x0B, 0xAC, 0x00, 0xC0, 0x0E, 0x40, 0x00, 0x81, 0x0B, 0x8D, 0x00, 0xC2, + 0x0E, 0x0B, 0x1C, 0x62, 0x00, 0xC4, 0x0E, 0x41, 0x00, 0xC5, 0x0E, 0x0C, 0x02, 0xBF, 0x80, 0xE7, + 0x00, 0xF8, 0x0B, 0xAA, 0x00, 0xFB, 0x0B, 0xAD, 0x02, 0xDF, 0x00, 0xC0, 0x0E, 0x40, 0x00, 0x81, + 0x0B, 0x89, 0x00, 0xC2, 0x0E, 0x08, 0x1C, 0x62, 0x00, 0xC4, 0x0E, 0x41, 0x00, 0xC5, 0x0E, 0x09, + 0x02, 0xBF, 0x80, 0xE7, 0x00, 0xF8, 0x0B, 0xA9, 0x00, 0xFB, 0x0B, 0xAC, 0x00, 0xC0, 0x0E, 0x40, + 0x00, 0x81, 0x0B, 0x91, 0x00, 0xC2, 0x0E, 0x0E, 0x1C, 0x62, 0x00, 0xC4, 0x0E, 0x41, 0x00, 0xC5, + 0x0E, 0x0F, 0x02, 0xBF, 0x80, 0xE7, 0x00, 0xF8, 0x0B, 0xAB, 0x00, 0xFB, 0x0B, 0xAE, 0x02, 0xDF, + 0x00, 0xC0, 0x0E, 0x40, 0x00, 0x81, 0x0B, 0x89, 0x00, 0xC2, 0x0E, 0x08, 0x1C, 0x62, 0x00, 0xC4, + 0x0E, 0x41, 0x00, 0xC5, 0x0E, 0x09, 0x02, 0xBF, 0x80, 0xE7, 0x00, 0xF8, 0x0B, 0xA9, 0x00, 0xFB, + 0x0B, 0xAC, 0x00, 0xC0, 0x0E, 0x40, 0x00, 0x81, 0x0B, 0x8D, 0x00, 0xC2, 0x0E, 0x0B, 0x1C, 0x62, + 0x00, 0xC4, 0x0E, 0x41, 0x00, 0xC5, 0x0E, 0x0C, 0x02, 0xBF, 0x80, 0xE7, 0x00, 0xF8, 0x0B, 0xAA, + 0x00, 0xFB, 0x0B, 0xAD, 0x00, 0xC0, 0x0E, 0x40, 0x00, 0x81, 0x0B, 0x91, 0x00, 0xC2, 0x0E, 0x0E, + 0x1C, 0x62, 0x00, 0xC4, 0x0E, 0x41, 0x00, 0xC5, 0x0E, 0x0F, 0x02, 0xBF, 0x80, 0xE7, 0x00, 0xF8, + 0x0B, 0xAB, 0x00, 0xFB, 0x0B, 0xAE, 0x02, 0xDF, 0x00, 0xC0, 0x0E, 0x40, 0x00, 0x81, 0x0B, 0x89, + 0x00, 0xC2, 0x0E, 0x08, 0x1C, 0x62, 0x00, 0xC4, 0x0E, 0x41, 0x00, 0xC5, 0x0E, 0x09, 0x02, 0xBF, + 0x80, 0xE7, 0x00, 0xF8, 0x0B, 0xA9, 0x00, 0xFB, 0x0B, 0xAC, 0x00, 0xC0, 0x0E, 0x43, 0x00, 0x81, + 0x0B, 0x97, 0x00, 0xC2, 0x0E, 0x0A, 0x1C, 0x62, 0x02, 0xBF, 0x81, 0xF9, 0x00, 0xF8, 0x0B, 0xAF, + 0x02, 0xDF, 0x00, 0xC0, 0x0E, 0x40, 0x00, 0x81, 0x0B, 0x89, 0x00, 0xC2, 0x0E, 0x08, 0x1C, 0x62, + 0x00, 0xC4, 0x0E, 0x41, 0x00, 0xC5, 0x0E, 0x09, 0x02, 0xBF, 0x80, 0xE7, 0x00, 0xF8, 0x0B, 0xA9, + 0x00, 0xFB, 0x0B, 0xAC, 0x00, 0xC0, 0x0E, 0x40, 0x00, 0x81, 0x0B, 0x8D, 0x00, 0xC2, 0x0E, 0x0B, + 0x1C, 0x62, 0x00, 0xC4, 0x0E, 0x41, 0x00, 0xC5, 0x0E, 0x0C, 0x02, 0xBF, 0x80, 0xE7, 0x00, 0xF8, + 0x0B, 0xAA, 0x00, 0xFB, 0x0B, 0xAD, 0x00, 0xC0, 0x0E, 0x43, 0x00, 0x81, 0x0B, 0x97, 0x00, 0xC2, + 0x0E, 0x0A, 0x1C, 0x62, 0x1C, 0x80, 0x00, 0xC5, 0x0E, 0x0D, 0x02, 0xBF, 0x80, 0xE7, 0x00, 0xF8, + 0x0B, 0xAF, 0x00, 0xFB, 0x0B, 0xB0, 0x02, 0xDF, 0x00, 0xC0, 0x0E, 0x40, 0x00, 0x81, 0x0B, 0x89, + 0x00, 0xC2, 0x0E, 0x08, 0x1C, 0x62, 0x00, 0xC4, 0x0E, 0x41, 0x00, 0xC5, 0x0E, 0x09, 0x02, 0xBF, + 0x80, 0xE7, 0x00, 0xF8, 0x0B, 0xA9, 0x00, 0xFB, 0x0B, 0xAC, 0x00, 0xC0, 0x0E, 0x40, 0x00, 0x81, + 0x0B, 0x91, 0x00, 0xC2, 0x0E, 0x0E, 0x1C, 0x62, 0x00, 0xC4, 0x0E, 0x41, 0x00, 0xC5, 0x0E, 0x0F, + 0x02, 0xBF, 0x80, 0xE7, 0x00, 0xF8, 0x0B, 0xAB, 0x00, 0xFB, 0x0B, 0xAE, 0x00, 0xC0, 0x0E, 0x43, + 0x00, 0x81, 0x0B, 0x95, 0x00, 0xC2, 0x0E, 0x10, 0x1C, 0x62, 0x1C, 0x80, 0x00, 0xC5, 0x0E, 0x0A, + 0x02, 0xBF, 0x80, 0xE7, 0x00, 0xF8, 0x0B, 0xB1, 0x00, 0xFB, 0x0B, 0xAF, 0x02, 0xDF, 0x00, 0xC0, + 0x0E, 0x40, 0x00, 0x81, 0x0B, 0x89, 0x00, 0xC2, 0x0E, 0x08, 0x1C, 0x62, 0x00, 0xC4, 0x0E, 0x41, + 0x00, 0xC5, 0x0E, 0x09, 0x02, 0xBF, 0x80, 0xE7, 0x00, 0xF8, 0x0B, 0xA9, 0x00, 0xFB, 0x0B, 0xAC, + 0x00, 0xC0, 0x0E, 0x40, 0x00, 0x81, 0x0B, 0x8D, 0x00, 0xC2, 0x0E, 0x0B, 0x1C, 0x62, 0x00, 0xC4, + 0x0E, 0x41, 0x00, 0xC5, 0x0E, 0x0C, 0x02, 0xBF, 0x80, 0xE7, 0x00, 0xF8, 0x0B, 0xAA, 0x00, 0xFB, + 0x0B, 0xAD, 0x00, 0xC0, 0x0E, 0x40, 0x00, 0x81, 0x0B, 0x91, 0x00, 0xC2, 0x0E, 0x0E, 0x1C, 0x62, + 0x00, 0xC4, 0x0E, 0x41, 0x00, 0xC5, 0x0E, 0x0F, 0x02, 0xBF, 0x80, 0xE7, 0x00, 0xF8, 0x0B, 0xAB, + 0x00, 0xFB, 0x0B, 0xAE, 0x00, 0xC0, 0x0E, 0x43, 0x00, 0x81, 0x0B, 0x97, 0x00, 0xC2, 0x0E, 0x0A, + 0x1C, 0x62, 0x1C, 0x80, 0x00, 0xC5, 0x0E, 0x0D, 0x02, 0xBF, 0x80, 0xE7, 0x00, 0xF8, 0x0B, 0xAF, + 0x00, 0xFB, 0x0B, 0xB0, 0x00, 0xC0, 0x0E, 0x43, 0x00, 0x81, 0x0B, 0x95, 0x00, 0xC2, 0x0E, 0x10, + 0x1C, 0x62, 0x02, 0xBF, 0x81, 0xF9, 0x00, 0xF8, 0x0B, 0xB1, 0x02, 0xDF, 0x00, 0xC0, 0x0E, 0x40, + 0x00, 0x81, 0x0B, 0x89, 0x00, 0xC2, 0x0E, 0x08, 0x00, 0x83, 0x0E, 0x44, 0x00, 0xC4, 0x0E, 0x41, + 0x00, 0xC5, 0x0E, 0x09, 0x02, 0xBF, 0x82, 0x82, 0x00, 0xF8, 0x0B, 0xA9, 0x00, 0xFB, 0x0B, 0xAC, + 0x02, 0xDF, 0x00, 0xC0, 0x0E, 0x40, 0x00, 0x81, 0x0B, 0x89, 0x00, 0xC2, 0x0E, 0x08, 0x00, 0x83, + 0x0E, 0x44, 0x00, 0xC4, 0x0E, 0x41, 0x00, 0xC5, 0x0E, 0x09, 0x02, 0xBF, 0x82, 0x82, 0x00, 0xF8, + 0x0B, 0xA9, 0x00, 0xFB, 0x0B, 0xAC, 0x00, 0xC0, 0x0E, 0x40, 0x00, 0x81, 0x0B, 0x8D, 0x00, 0xC2, + 0x0E, 0x0B, 0x00, 0x83, 0x0E, 0x44, 0x00, 0xC4, 0x0E, 0x41, 0x00, 0xC5, 0x0E, 0x0C, 0x02, 0xBF, + 0x82, 0x82, 0x00, 0xF8, 0x0B, 0xAA, 0x00, 0xFB, 0x0B, 0xAD, 0x02, 0xDF, 0x00, 0xC0, 0x0E, 0x40, + 0x00, 0x81, 0x0B, 0x89, 0x00, 0xC2, 0x0E, 0x08, 0x00, 0x83, 0x0E, 0x44, 0x00, 0xC4, 0x0E, 0x41, + 0x00, 0xC5, 0x0E, 0x09, 0x02, 0xBF, 0x82, 0x82, 0x00, 0xF8, 0x0B, 0xA9, 0x00, 0xFB, 0x0B, 0xAC, + 0x00, 0xC0, 0x0E, 0x40, 0x00, 0x81, 0x0B, 0x91, 0x00, 0xC2, 0x0E, 0x0E, 0x00, 0x83, 0x0E, 0x44, + 0x00, 0xC4, 0x0E, 0x41, 0x00, 0xC5, 0x0E, 0x0F, 0x02, 0xBF, 0x82, 0x82, 0x00, 0xF8, 0x0B, 0xAB, + 0x00, 0xFB, 0x0B, 0xAE, 0x02, 0xDF, 0x00, 0xC0, 0x0E, 0x40, 0x00, 0x81, 0x0B, 0x89, 0x00, 0xC2, + 0x0E, 0x08, 0x00, 0x83, 0x0E, 0x44, 0x00, 0xC4, 0x0E, 0x41, 0x00, 0xC5, 0x0E, 0x09, 0x02, 0xBF, + 0x82, 0x82, 0x00, 0xF8, 0x0B, 0xA9, 0x00, 0xFB, 0x0B, 0xAC, 0x00, 0xC0, 0x0E, 0x40, 0x00, 0x81, + 0x0B, 0x8D, 0x00, 0xC2, 0x0E, 0x0B, 0x00, 0x83, 0x0E, 0x44, 0x00, 0xC4, 0x0E, 0x41, 0x00, 0xC5, + 0x0E, 0x0C, 0x02, 0xBF, 0x82, 0x82, 0x00, 0xF8, 0x0B, 0xAA, 0x00, 0xFB, 0x0B, 0xAD, 0x00, 0xC0, + 0x0E, 0x40, 0x00, 0x81, 0x0B, 0x91, 0x00, 0xC2, 0x0E, 0x0E, 0x00, 0x83, 0x0E, 0x44, 0x00, 0xC4, + 0x0E, 0x41, 0x00, 0xC5, 0x0E, 0x0F, 0x02, 0xBF, 0x82, 0x82, 0x00, 0xF8, 0x0B, 0xAB, 0x00, 0xFB, + 0x0B, 0xAE, 0x02, 0xDF, 0x00, 0xC0, 0x0E, 0x40, 0x00, 0x81, 0x0B, 0x89, 0x00, 0xC2, 0x0E, 0x08, + 0x00, 0x83, 0x0E, 0x44, 0x00, 0xC4, 0x0E, 0x41, 0x00, 0xC5, 0x0E, 0x09, 0x02, 0xBF, 0x82, 0x82, + 0x00, 0xF8, 0x0B, 0xA9, 0x00, 0xFB, 0x0B, 0xAC, 0x00, 0xC0, 0x0E, 0x43, 0x00, 0x81, 0x0B, 0x97, + 0x00, 0xC2, 0x0E, 0x0A, 0x00, 0x83, 0x0E, 0x44, 0x02, 0xBF, 0x84, 0x5D, 0x00, 0xF8, 0x0B, 0xAF, + 0x02, 0xDF, 0x00, 0xC0, 0x0E, 0x40, 0x00, 0x81, 0x0B, 0x89, 0x00, 0xC2, 0x0E, 0x08, 0x00, 0x83, + 0x0E, 0x44, 0x00, 0xC4, 0x0E, 0x41, 0x00, 0xC5, 0x0E, 0x09, 0x02, 0xBF, 0x82, 0x82, 0x00, 0xF8, + 0x0B, 0xA9, 0x00, 0xFB, 0x0B, 0xAC, 0x00, 0xC0, 0x0E, 0x40, 0x00, 0x81, 0x0B, 0x8D, 0x00, 0xC2, + 0x0E, 0x0B, 0x00, 0x83, 0x0E, 0x44, 0x00, 0xC4, 0x0E, 0x41, 0x00, 0xC5, 0x0E, 0x0C, 0x02, 0xBF, + 0x82, 0x82, 0x00, 0xF8, 0x0B, 0xAA, 0x00, 0xFB, 0x0B, 0xAD, 0x00, 0xC0, 0x0E, 0x43, 0x00, 0x81, + 0x0B, 0x97, 0x00, 0xC2, 0x0E, 0x0A, 0x00, 0x83, 0x0E, 0x44, 0x1C, 0x80, 0x00, 0xC5, 0x0E, 0x0D, + 0x02, 0xBF, 0x82, 0x82, 0x00, 0xF8, 0x0B, 0xAF, 0x00, 0xFB, 0x0B, 0xB0, 0x02, 0xDF, 0x00, 0xC0, + 0x0E, 0x40, 0x00, 0x81, 0x0B, 0x89, 0x00, 0xC2, 0x0E, 0x08, 0x00, 0x83, 0x0E, 0x44, 0x00, 0xC4, + 0x0E, 0x41, 0x00, 0xC5, 0x0E, 0x09, 0x02, 0xBF, 0x82, 0x82, 0x00, 0xF8, 0x0B, 0xA9, 0x00, 0xFB, + 0x0B, 0xAC, 0x00, 0xC0, 0x0E, 0x40, 0x00, 0x81, 0x0B, 0x91, 0x00, 0xC2, 0x0E, 0x0E, 0x00, 0x83, + 0x0E, 0x44, 0x00, 0xC4, 0x0E, 0x41, 0x00, 0xC5, 0x0E, 0x0F, 0x02, 0xBF, 0x82, 0x82, 0x00, 0xF8, + 0x0B, 0xAB, 0x00, 0xFB, 0x0B, 0xAE, 0x00, 0xC0, 0x0E, 0x43, 0x00, 0x81, 0x0B, 0x95, 0x00, 0xC2, + 0x0E, 0x10, 0x00, 0x83, 0x0E, 0x44, 0x1C, 0x80, 0x00, 0xC5, 0x0E, 0x0A, 0x02, 0xBF, 0x82, 0x82, + 0x00, 0xF8, 0x0B, 0xB1, 0x00, 0xFB, 0x0B, 0xAF, 0x02, 0xDF, 0x00, 0xC0, 0x0E, 0x40, 0x00, 0x81, + 0x0B, 0x89, 0x00, 0xC2, 0x0E, 0x08, 0x00, 0x83, 0x0E, 0x44, 0x00, 0xC4, 0x0E, 0x41, 0x00, 0xC5, + 0x0E, 0x09, 0x02, 0xBF, 0x82, 0x82, 0x00, 0xF8, 0x0B, 0xA9, 0x00, 0xFB, 0x0B, 0xAC, 0x00, 0xC0, + 0x0E, 0x40, 0x00, 0x81, 0x0B, 0x8D, 0x00, 0xC2, 0x0E, 0x0B, 0x00, 0x83, 0x0E, 0x44, 0x00, 0xC0, + 0x0E, 0x41, 0x00, 0xC5, 0x0E, 0x0C, 0x02, 0xBF, 0x82, 0x82, 0x00, 0xF8, 0x0B, 0xAA, 0x00, 0xFB, + 0x0B, 0xAD, 0x00, 0xC0, 0x0E, 0x40, 0x00, 0x81, 0x0B, 0x91, 0x00, 0xC2, 0x0E, 0x0E, 0x00, 0x83, + 0x0E, 0x44, 0x00, 0xC4, 0x0E, 0x41, 0x00, 0xC5, 0x0E, 0x0F, 0x02, 0xBF, 0x82, 0x82, 0x00, 0xF8, + 0x0B, 0xAB, 0x00, 0xFB, 0x0B, 0xAE, 0x00, 0xC0, 0x0E, 0x43, 0x00, 0x81, 0x0B, 0x97, 0x00, 0xC2, + 0x0E, 0x0A, 0x00, 0x83, 0x0E, 0x44, 0x1C, 0x80, 0x00, 0xC5, 0x0E, 0x0D, 0x02, 0xBF, 0x82, 0x82, + 0x00, 0xF8, 0x0B, 0xAF, 0x00, 0xFB, 0x0B, 0xB0, 0x00, 0xC0, 0x0E, 0x43, 0x00, 0x81, 0x0B, 0x95, + 0x00, 0xC2, 0x0E, 0x10, 0x00, 0x83, 0x0E, 0x44, 0x02, 0xBF, 0x84, 0x5D, 0x00, 0xF8, 0x0B, 0xB1, + 0x02, 0xDF, 0x00, 0xC0, 0x0E, 0x40, 0x00, 0x81, 0x0B, 0x89, 0x00, 0xC2, 0x0E, 0x08, 0x1C, 0x62, + 0x00, 0xC4, 0x0E, 0x41, 0x00, 0xC5, 0x0E, 0x09, 0x02, 0xBF, 0x80, 0xE7, 0x00, 0xF8, 0x0B, 0xA9, + 0x00, 0xFB, 0x0B, 0xAC, 0x00, 0xC0, 0x0E, 0x43, 0x00, 0x81, 0x0B, 0x91, 0x00, 0xC2, 0x0E, 0x0E, + 0x1C, 0x62, 0x1C, 0x80, 0x00, 0xC5, 0x0E, 0x0F, 0x02, 0xBF, 0x80, 0xE7, 0x00, 0xF8, 0x0B, 0xAB, + 0x00, 0xFB, 0x0B, 0xAE, 0x02, 0xDF, 0x00, 0xC0, 0x0E, 0x40, 0x00, 0x81, 0x0B, 0x89, 0x00, 0xC2, + 0x0E, 0x08, 0x1C, 0x62, 0x00, 0xC4, 0x0E, 0x41, 0x00, 0xC5, 0x0E, 0x09, 0x02, 0xBF, 0x80, 0xE7, + 0x00, 0xF8, 0x0B, 0xA9, 0x00, 0xFB, 0x0B, 0xAC, 0x00, 0xC0, 0x0E, 0x43, 0x00, 0x81, 0x0B, 0x91, + 0x00, 0xC2, 0x0E, 0x0E, 0x1C, 0x62, 0x1C, 0x80, 0x00, 0xC5, 0x0E, 0x0F, 0x02, 0xBF, 0x80, 0xE7, + 0x00, 0xF8, 0x0B, 0xAB, 0x00, 0xFB, 0x0B, 0xAE, 0x00, 0xC0, 0x0E, 0x40, 0x00, 0x81, 0x0B, 0x8D, + 0x00, 0xC2, 0x0E, 0x0B, 0x1C, 0x62, 0x00, 0xC4, 0x0E, 0x41, 0x00, 0xC5, 0x0E, 0x0C, 0x02, 0xBF, + 0x80, 0xE7, 0x00, 0xF8, 0x0B, 0xAA, 0x00, 0xFB, 0x0B, 0xAD, 0x00, 0xC0, 0x0E, 0x43, 0x00, 0x81, + 0x0B, 0x99, 0x00, 0xC2, 0x0E, 0x0D, 0x1C, 0x62, 0x02, 0xBF, 0x81, 0xF9, 0x00, 0xF8, 0x0B, 0xB0, + 0x02, 0xDF, 0x00, 0xC0, 0x0E, 0x40, 0x00, 0x81, 0x0B, 0x89, 0x00, 0xC2, 0x0E, 0x08, 0x00, 0x83, + 0x0E, 0x44, 0x00, 0xC4, 0x0E, 0x41, 0x00, 0xC5, 0x0E, 0x09, 0x02, 0xBF, 0x82, 0x82, 0x00, 0xF8, + 0x0B, 0xA9, 0x00, 0xFB, 0x0B, 0xAC, 0x00, 0xC0, 0x0E, 0x43, 0x00, 0x81, 0x0B, 0x91, 0x00, 0xC2, + 0x0E, 0x0E, 0x00, 0x83, 0x0E, 0x44, 0x1C, 0x80, 0x00, 0xC5, 0x0E, 0x0F, 0x02, 0xBF, 0x82, 0x82, + 0x00, 0xF8, 0x0B, 0xAB, 0x00, 0xFB, 0x0B, 0xAE, 0x02, 0xDF, 0x00, 0xC0, 0x0E, 0x40, 0x00, 0x81, + 0x0B, 0x89, 0x00, 0xC2, 0x0E, 0x08, 0x00, 0x83, 0x0E, 0x44, 0x00, 0xC4, 0x0E, 0x41, 0x00, 0xC5, + 0x0E, 0x09, 0x02, 0xBF, 0x82, 0x82, 0x00, 0xF8, 0x0B, 0xA9, 0x00, 0xFB, 0x0B, 0xAC, 0x00, 0xC0, + 0x0E, 0x43, 0x00, 0x81, 0x0B, 0x91, 0x00, 0xC2, 0x0E, 0x0E, 0x00, 0x83, 0x0E, 0x44, 0x1C, 0x80, + 0x00, 0xC5, 0x0E, 0x0F, 0x02, 0xBF, 0x82, 0x82, 0x00, 0xF8, 0x0B, 0xAB, 0x00, 0xFB, 0x0B, 0xAE, + 0x00, 0xC0, 0x0E, 0x40, 0x00, 0x81, 0x0B, 0x8D, 0x00, 0xC2, 0x0E, 0x0B, 0x00, 0x83, 0x0E, 0x44, + 0x00, 0xC4, 0x0E, 0x41, 0x00, 0xC5, 0x0E, 0x0C, 0x02, 0xBF, 0x82, 0x82, 0x00, 0xF8, 0x0B, 0xAA, + 0x00, 0xFB, 0x0B, 0xAD, 0x00, 0xC0, 0x0E, 0x43, 0x00, 0x81, 0x0B, 0x99, 0x00, 0xC2, 0x0E, 0x0D, + 0x00, 0x83, 0x0E, 0x44, 0x02, 0xBF, 0x84, 0x5D, 0x00, 0xF8, 0x0B, 0xB0, 0x02, 0xDF, 0x00, 0x82, + 0x01, 0x3E, 0x01, 0xBC, 0x02, 0x48, 0x04, 0x13, 0x04, 0x27, 0x01, 0x65, 0x05, 0x74, 0x0B, 0x37, + 0x01, 0x5F, 0x04, 0x78, 0x04, 0x74, 0x04, 0x76, 0x01, 0xA9, 0x04, 0x3B, 0x04, 0x7A, 0x0B, 0xB1, + 0x01, 0x75, 0x07, 0x68, 0x07, 0x7A, 0x07, 0x9D, 0x07, 0xC0, 0x07, 0xF4, 0x08, 0x11, 0x08, 0x44, + 0x08, 0x77, 0x08, 0xC6, 0x08, 0xD9, 0x08, 0xFE, 0x09, 0x23, 0x09, 0x5A, 0x09, 0x79, 0x09, 0xAF, + 0x09, 0xE5, 0x0A, 0x39, 0x0A, 0x5B, 0x07, 0x68, 0x07, 0x68, 0x07, 0x68, 0x07, 0x68, 0x07, 0x68, + 0x07, 0x68, 0x0A, 0x99, 0x0A, 0xBD, 0x07, 0x68, 0x07, 0x68, 0x07, 0x68, 0x07, 0x68, 0x07, 0x68, + 0x07, 0x68, 0x05, 0xA8, 0x06, 0x5D, 0x07, 0x07, 0x10, 0x00, 0x12, 0x00, 0x14, 0x00, 0x8E, 0x00, + 0x81, 0x00, 0x89, 0x70, 0x19, 0x1C, 0x2E, 0xCE, 0x2C, 0xCF, 0x16, 0xCD, 0x0E, 0x80, 0x16, 0xC9, + 0x00, 0x00, 0x16, 0xCB, 0x01, 0x00, 0x1F, 0x7E, 0x1F, 0x3C, 0x81, 0x00, 0x26, 0xC9, 0x02, 0xA0, + 0x00, 0x04, 0x02, 0x9C, 0x0B, 0x46, 0x19, 0x1E, 0x19, 0x1C, 0x2E, 0xCE, 0x2C, 0xCF, 0x16, 0xCD, + 0x02, 0x80, 0x16, 0xC9, 0x00, 0x00, 0x16, 0xCB, 0x02, 0x80, 0x1C, 0x80, 0x00, 0x80, 0x02, 0x80, + 0x00, 0xC1, 0x0E, 0x1B, 0x00, 0x85, 0x00, 0x00, 0x00, 0x89, 0x00, 0x7F, 0x00, 0x82, 0x0F, 0x00, + 0x00, 0x83, 0x16, 0xB4, 0x1C, 0xE3, 0x81, 0x00, 0x26, 0xC9, 0x02, 0xA0, 0x00, 0x04, 0x02, 0x9C, + 0x0B, 0x64, 0x8F, 0x00, 0x8A, 0x78, 0x8C, 0x68, 0xF1, 0x00, 0x1A, 0x3F, 0x84, 0xE3, 0x10, 0x7E, + 0xF2, 0xE3, 0xF2, 0xE7, 0xF2, 0x78, 0x6E, 0x68, 0xF1, 0x32, 0x1A, 0x3F, 0x11, 0x9E, 0x0B, 0x80, + 0x1C, 0x67, 0x84, 0xE3, 0x10, 0x7E, 0xF2, 0xE3, 0xF2, 0xE7, 0xF2, 0x78, 0x6E, 0x68, 0xF1, 0x32, + 0x1A, 0x3F, 0x1C, 0x67, 0x84, 0xE3, 0x10, 0x7E, 0xF2, 0xE3, 0xF2, 0xE7, 0xF2, 0x00, 0x6E, 0x00, + 0x1B, 0x5E, 0x00, 0xE1, 0x0E, 0x1B, 0x00, 0x80, 0x02, 0x80, 0x00, 0x83, 0x0F, 0x00, 0x00, 0x81, + 0x00, 0x00, 0x00, 0x82, 0x01, 0x40, 0x00, 0x89, 0xFF, 0xFF, 0x89, 0x00, 0x81, 0x00, 0x8F, 0x00, + 0x11, 0xA0, 0x0B, 0xA0, 0x19, 0x7F, 0x99, 0x30, 0x1B, 0x1E, 0x1B, 0x3F, 0x7D, 0x29, 0x1B, 0x5F, + 0x1B, 0x5D, 0x8E, 0x00, 0x1F, 0xDB, 0x1F, 0x99, 0x2E, 0xCE, 0x2C, 0xCF, 0x16, 0xCD, 0x0E, 0x80, + 0x16, 0xC9, 0x00, 0x01, 0x16, 0xCB, 0x01, 0x00, 0x02, 0xBF, 0x05, 0x5C, 0x1C, 0x04, 0x02, 0x9F, + 0x00, 0x68, 0x8E, 0x00, 0x81, 0x00, 0x89, 0x70, 0x19, 0x1C, 0x2E, 0xCE, 0x2C, 0xCF, 0x16, 0xCD, + 0x07, 0xC0, 0x16, 0xC9, 0x00, 0x01, 0x16, 0xCB, 0x05, 0x00, 0x02, 0xBF, 0x05, 0x5C, 0x81, 0x00, + 0x89, 0x70, 0x19, 0x1C, 0x2E, 0xCE, 0x2C, 0xCF, 0x16, 0xCD, 0x07, 0xC0, 0x16, 0xC9, 0x00, 0x00, + 0x89, 0x00, 0x0D, 0x20, 0x2D, 0xCB, 0x4C, 0x00, 0x1C, 0x80, 0x00, 0x80, 0x07, 0xC0, 0x00, 0x83, + 0x00, 0x00, 0x1C, 0x43, 0x0A, 0x00, 0x27, 0xC9, 0x03, 0xA0, 0x00, 0x04, 0x02, 0x9C, 0x0B, 0xD3, + 0x2E, 0xCE, 0x2C, 0xCF, 0x16, 0xCD, 0x07, 0xD0, 0x16, 0xC9, 0x00, 0x00, 0x16, 0xCB, 0x04, 0xE0, + 0x8F, 0x00, 0x80, 0xF0, 0x80, 0xC0, 0x6A, 0x00, 0x48, 0x00, 0x11, 0x4F, 0x0B, 0xEE, 0x80, 0xF0, + 0x80, 0xC0, 0x6B, 0x32, 0x49, 0x22, 0x80, 0xF0, 0x80, 0xC0, 0x6A, 0x3A, 0x48, 0x2A, 0x80, 0xF0, + 0x80, 0xC0, 0x6B, 0x32, 0x49, 0x22, 0x1B, 0x5F, 0x1B, 0x5D, 0x80, 0xF0, 0x80, 0xC0, 0x68, 0x00, + 0x7C, 0x00, 0x4A, 0x00, 0x11, 0x4F, 0x0C, 0x05, 0x80, 0xF0, 0x80, 0xC0, 0x69, 0x32, 0x7D, 0x00, + 0x4B, 0x22, 0x80, 0xF0, 0x80, 0xC0, 0x68, 0x3A, 0x7C, 0x00, 0x4A, 0x2A, 0x80, 0xF0, 0x80, 0xC0, + 0x69, 0x32, 0x7D, 0x00, 0x4B, 0x22, 0x1B, 0x5F, 0x1B, 0x5D, 0x1C, 0x04, 0x02, 0x9F, 0x00, 0x68, + 0x8E, 0x00, 0x16, 0xFC, 0xEC, 0xC0, 0x1F, 0xCC, 0x1D, 0x9E, 0x2E, 0xFD, 0x26, 0xFC, 0x02, 0xA0, + 0x80, 0x00, 0x02, 0x9C, 0x0C, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xFF, 0x8E, 0x00, + 0x00, 0xF0, 0x0E, 0x17, 0x00, 0xFE, 0x0E, 0x18, 0x00, 0xFC, 0x0E, 0x19, 0x1F, 0xCC, 0x1D, 0x9E, + 0x16, 0xFC, 0xFE, 0xED, 0x2E, 0xFD, 0x26, 0xFC, 0x02, 0xA0, 0x80, 0x00, 0x02, 0x9C, 0x0C, 0x2B, + 0x00, 0xD0, 0x0E, 0x17, 0x00, 0xDE, 0x0E, 0x18, 0x00, 0xDC, 0x0E, 0x19, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0xFF, 0x8E, 0x00, 0x1D, 0xBC, 0x1D, 0xBE, 0x81, 0x00, 0x00, 0xDE, + 0x0B, 0xB7, 0x06, 0x01, 0x02, 0x95, 0x0C, 0x47, 0x0E, 0x00, 0x00, 0xFE, 0x0B, 0x87, 0x1F, 0xCD, + 0x1F, 0x8D, 0x02, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xFF, + 0x8E, 0x00, 0x1D, 0xBC, 0x1D, 0xBE, 0x81, 0x00, 0x00, 0xDE, 0x0B, 0xB7, 0x06, 0x01, 0x02, 0x95, + 0x0C, 0x5F, 0x0E, 0x00, 0x00, 0xFE, 0x0B, 0x87, 0x1F, 0xCD, 0x1F, 0x8D, 0x02, 0xFF, 0x81, 0x00, + 0x00, 0xDE, 0x0B, 0x88, 0x06, 0x01, 0x02, 0x95, 0x0C, 0x71, 0x00, 0xDE, 0x0B, 0xDA, 0x2E, 0xDA, + 0x00, 0xDE, 0x0B, 0xDB, 0x2E, 0xDB, 0x00, 0xDE, 0x0B, 0xDC, 0x2E, 0xDC, 0x1F, 0xCD, 0x1F, 0x8D, + 0x02, 0xFF, 0x00, 0xDE, 0x0B, 0xDA, 0x2E, 0xDA, 0x26, 0xDB, 0x2E, 0xDB, 0x26, 0xDC, 0x2E, 0xDC, + 0x81, 0x00, 0x00, 0xDC, 0x0B, 0xDD, 0x76, 0x00, 0x00, 0xFC, 0x0B, 0xDD, 0x81, 0x00, 0x1F, 0xCD, + 0x1F, 0x8D, 0x02, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xFF, 0x0C, 0x9F, 0x0C, 0xA2, 0x0C, 0xDA, + 0x0C, 0xDD, 0x8E, 0x00, 0x81, 0x00, 0x89, 0x00, 0x02, 0xBF, 0x0C, 0xE0, 0x27, 0xFF, 0x00, 0x9E, + 0x0C, 0x8D, 0x4C, 0x00, 0x1C, 0x7E, 0x03, 0x13, 0x1C, 0x7F, 0x17, 0x6F, 0x00, 0x21, 0x02, 0x9F, + 0x00, 0x30, 0x00, 0x21, 0x81, 0x00, 0x89, 0x00, 0x02, 0xBF, 0x0C, 0xE0, 0x24, 0xFF, 0x02, 0xBF, + 0x0C, 0xE6, 0x25, 0xFF, 0x02, 0xBF, 0x0C, 0xE6, 0x27, 0xFF, 0x2E, 0xCE, 0x2C, 0xCF, 0x16, 0xC9, + 0x00, 0x01, 0x2F, 0xCD, 0x2D, 0xCB, 0x81, 0x00, 0x89, 0x00, 0x02, 0xBF, 0x0C, 0xE0, 0x24, 0xFF, + 0x1C, 0x9E, 0x1C, 0xBC, 0x02, 0xBF, 0x0C, 0xE6, 0x25, 0xFF, 0x02, 0xBF, 0x0C, 0xE6, 0x27, 0xFF, + 0x1C, 0xDF, 0x1C, 0xFD, 0x81, 0x00, 0x02, 0xBF, 0x0C, 0xE0, 0x26, 0xFF, 0x1C, 0x1E, 0x89, 0x00, + 0x02, 0xBF, 0x0C, 0xE6, 0x20, 0xFF, 0x1F, 0x5F, 0x02, 0xBF, 0x0C, 0xE0, 0x21, 0xFF, 0x02, 0xBF, + 0x0C, 0xE0, 0x23, 0xFF, 0x26, 0xC9, 0x02, 0xA0, 0x00, 0x04, 0x02, 0x9C, 0x0C, 0xD2, 0x02, 0x9F, + 0x80, 0xB5, 0x00, 0x21, 0x02, 0x9F, 0x80, 0x00, 0x00, 0x21, 0x02, 0x9F, 0x00, 0x45, 0x00, 0x21, + 0x26, 0xFE, 0x02, 0xC0, 0x80, 0x00, 0x02, 0x9C, 0x0C, 0xE0, 0x02, 0xDF, 0x27, 0xFE, 0x03, 0xC0, + 0x80, 0x00, 0x02, 0x9C, 0x0C, 0xE6, 0x02, 0xDF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +u16 dspSlaveLength = sizeof(dspSlave); + +#ifdef __cplusplus +} +#endif diff --git a/src/musyx/runtime/dolphin/hardware.c b/src/musyx/runtime/dolphin/hardware.c new file mode 100644 index 00000000..80f0bee3 --- /dev/null +++ b/src/musyx/runtime/dolphin/hardware.c @@ -0,0 +1,504 @@ +#include "musyx/assert.h" +#include "musyx/hardware.h" +#include "musyx/stream.h" +#include "musyx/synth.h" +#include "musyx/sal.h" + +extern void DCStoreRange(void* addr, u32 nBytes); + +static volatile const u16 itdOffTab[128] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, + 5, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, 11, 11, 12, 12, 12, 13, 13, 13, 14, 14, 15, 15, 15, 16, + 16, 17, 17, 17, 18, 18, 19, 19, 19, 20, 20, 20, 21, 21, 22, 22, 22, 23, 23, 23, 24, 24, 24, 25, 25, 25, 26, 26, 26, 27, 27, 27, + 28, 28, 28, 28, 29, 29, 29, 29, 29, 30, 30, 30, 30, 30, 31, 31, 31, 31, 31, 31, 31, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, +}; + +//SND_PROFILE_INFO prof; + +u8 salFrame; +u8 salAuxFrame; +u8 salNumVoices; +u8 salMaxStudioNum; +SND_HOOKS salHooks; +u8 salTimeOffset; +void hwSetTimeOffset(u8 offset); + +static void snd_handle_irq() { + u8 r; // r31 + u8 i; // r30 + u8 v; // r29 + if (sndActive == 0) { + return; + } + + streamCorrectLoops(); + hwIRQEnterCritical(); + // sndProfStartPCM(&prof.dspCtrl); + salCtrlDsp(salAiGetDest()); + // sndProfStopPMC(&prof.dspCtrl); + hwIRQLeaveCritical(); + hwIRQEnterCritical(); + // sndProfStartPCM(&prof.auxProcessing); + salHandleAuxProcessing(); + // sndProfStopPMC(&prof.auxProcessing); + hwIRQLeaveCritical(); + hwIRQEnterCritical(); + salFrame ^= 1; + salAuxFrame = (salAuxFrame + 1) % 3; + + for (v = 0; v < salNumVoices; ++v) { + for (i = 0; i < 5; ++i) { + dspVoice[v].changed[i] = 0; + } + } + + // sndProfStartPMC(&prof.sequencer); + // sndProfPausePMC(&prof.sequencer); + // sndProfStartPMC(&prof.synthesizer); + // sndProfPausePMC(&prof.synthesizer); + hwIRQLeaveCritical(); + for (r = 0; r < 5; ++r) { + hwIRQEnterCritical(); + hwSetTimeOffset(r); + // sndProfStartPMC(&prof.sequencer); + seqHandle(256); + // sndProfPausePMC(&prof.sequencer); + // sndProfStartPMC(&prof.synthesizer); + synthHandle(256); + // sndProfPausePMC(&prof.synthesizer); + hwIRQLeaveCritical(); + } + + // sndProfStopPMC(&prof.sequencer); + // sndProfStopPMC(&prof.synthesizer); + hwIRQEnterCritical(); + hwSetTimeOffset(0); + // sndProfStartPMC(&prof.emitters); + s3dHandle(); + // sndProfStopPMC(&prof.emitters); + hwIRQLeaveCritical(); + hwIRQEnterCritical(); + // sndProfStartPMC(&prof.streaming); + streamHandle(); + // sndProfStopPMC(&prof.streaming); + hwIRQLeaveCritical(); + hwIRQEnterCritical(); + vsSampleUpdates(); + hwIRQLeaveCritical(); + // sndProfUpdateMisc(&prof); + + // if (sndProfUserCallback) { + // sndProfUserCallback(&prof); + // } +} + +s32 hwInit(u32* frq, u16 numVoices, u16 numStudios, u32 flags) { + MUSY_DEBUG("Entering hwInit()\n\n"); + hwInitIrq(); + salFrame = 0; + salAuxFrame = 0; + salMessageCallback = NULL; + if (salInitAi(snd_handle_irq, flags, frq) != 0) { + MUSY_DEBUG("salInitAi() is done.\n\n"); + if (salInitDspCtrl(numVoices, numStudios, (flags & 1) != 0) != 0) { + MUSY_DEBUG("salInitDspCtrl() is done.\n\n"); + if (salInitDsp(flags)) { + MUSY_DEBUG("salInitDsp() is done.\n\n"); + hwEnableIrq(); + MUSY_DEBUG("Starting AI DMA...\n\n"); + salStartAi(); + MUSY_DEBUG("hwInit() done.\n\n"); + return 0; + } + MUSY_DEBUG("Could not initialize DSP.\n"); + } else { + MUSY_DEBUG("Could not initialize DSP control logic.\n"); + } + } else { + MUSY_DEBUG("Could not initialize AI.\n"); + } + return -1; +} + +void hwExit() { + hwDisableIrq(); + salExitDsp(); + salExitDspCtrl(); + salExitAi(); + hwEnableIrq(); + hwExitIrq(); +} + +void hwSetTimeOffset(u8 offset) { salTimeOffset = offset; } + +u8 hwGetTimeOffset() { return salTimeOffset; } + +u32 hwIsActive(u32 v) { return dspVoice[v].state != 0; } +u32 hwGlobalActivity() { return 0; } + +void hwSetMesgCallback(SND_MESSAGE_CALLBACK callback) { salMessageCallback = callback; } + +void hwSetPriority(u32 v, u32 prio) { dspVoice[v].prio = prio; } + +void hwInitSamplePlayback(u32 v, u16 smpID, void* newsmp, u32 set_defadsr, u32 prio, u32 callbackUserValue, u32 setSRC, u8 itdMode) { + unsigned char i; // r30 + unsigned long bf; // r29 + bf = 0; + for (i = 0; i <= salTimeOffset; ++i) { + bf |= dspVoice[v].changed[i] & 0x20; + dspVoice[v].changed[i] = 0; + } + + dspVoice[v].changed[0] = bf; + dspVoice[v].prio = prio; + dspVoice[v].mesgCallBackUserValue = callbackUserValue; + dspVoice[v].flags = 0; + dspVoice[v].smp_id = smpID; + dspVoice[v].smp_info = *(SAMPLE_INFO*)newsmp; + + if (set_defadsr != 0) { + dspVoice[v].adsr.mode = 0; + dspVoice[v].adsr.data.dls.aTime = 0; + dspVoice[v].adsr.data.dls.dTime = 0; + dspVoice[v].adsr.data.dls.sLevel = 0x7FFF; + dspVoice[v].adsr.data.dls.rTime = 0; + } + + dspVoice[v].lastUpdate.pitch = 0xff; + dspVoice[v].lastUpdate.vol = 0xff; + dspVoice[v].lastUpdate.volA = 0xff; + dspVoice[v].lastUpdate.volB = 0xff; + + if (setSRC != 0) { + hwSetSRCType(v, 0); + hwSetPolyPhaseFilter(v, 1); + } + + hwSetITDMode(v, itdMode); +} + +void hwBreak(s32 vid) { + if (dspVoice[vid].state == 1 && salTimeOffset == 0) { + dspVoice[vid].startupBreak = 1; + } + + dspVoice[vid].changed[salTimeOffset] |= 0x20; +} + +void hwSetADSR(u32 v, void* _adsr, u8 mode) { + u32 sl; // r29 + ADSR_INFO* adsr = (ADSR_INFO*)_adsr; // r30 + + switch (mode) { + case 0: { + dspVoice[v].adsr.mode = 0; + dspVoice[v].adsr.data.linear.aTime = adsr->data.linear.atime; + dspVoice[v].adsr.data.linear.dTime = adsr->data.linear.dtime; + sl = adsr->data.linear.slevel << 3; + if (sl > 0x7fff) { + sl = 0x7fff; + } + + dspVoice[v].adsr.data.linear.sLevel = sl; + dspVoice[v].adsr.data.linear.rTime = adsr->data.linear.rtime; + break; + } + case 1: + case 2: + dspVoice[v].adsr.mode = 1; + dspVoice[v].adsr.data.dls.aMode = 0; + if (mode == 1) { + dspVoice[v].adsr.data.dls.aTime = adsrConvertTimeCents(adsr->data.dls.atime) & 0xFFFF; + dspVoice[v].adsr.data.dls.dTime = adsrConvertTimeCents(adsr->data.dls.dtime) & 0xFFFF; + + sl = adsr->data.dls.slevel >> 2; + if (sl > 0x3ff) { + sl = 0x3ff; + } + + dspVoice[v].adsr.data.dls.sLevel = 193 - dspScale2IndexTab[sl]; + } else { + dspVoice[v].adsr.data.dls.aTime = adsr->data.dls.atime & 0xFFFF; + dspVoice[v].adsr.data.dls.dTime = adsr->data.dls.dtime & 0xFFFF; + dspVoice[v].adsr.data.dls.sLevel = adsr->data.dls.slevel; + } + + dspVoice[v].adsr.data.dls.rTime = adsr->data.dls.rtime; + } + + dspVoice[v].changed[0] |= 0x10; +} + +void hwSetVirtualSampleLoopBuffer(u32 voice, void* addr, u32 len) { + dspVoice[voice].vSampleInfo.loopBufferAddr = addr; + dspVoice[voice].vSampleInfo.loopBufferLength = len; +} + +u32 hwGetVirtualSampleState(u32 voice) { return dspVoice[voice].vSampleInfo.inLoopBuffer; } + +u8 hwGetSampleType(u32 voice) { return dspVoice[voice].smp_info.compType; } + +u16 hwGetSampleID(u32 voice) { return dspVoice[voice].smp_id; } + +void hwSetStreamLoopPS(u32 voice, u8 ps) { dspVoice[voice].streamLoopPS = ps; } + +void hwStart(u32 v, u8 studio) { + dspVoice[v].singleOffset = salTimeOffset; + salActivateVoice(&dspVoice[v], studio); +} + +void hwKeyOff(u32 v) { dspVoice[v].changed[salTimeOffset] |= 0x40; } + +void hwSetPitch(unsigned long v, unsigned short speed) { + struct DSPvoice* dsp_vptr = &dspVoice[v]; + + if (speed >= 0x4000) { + speed = 0x3fff; + } + + if (dsp_vptr->lastUpdate.pitch != 0xff && dsp_vptr->pitch[dsp_vptr->lastUpdate.pitch] == speed * 16) { + return; + } + + dsp_vptr->pitch[salTimeOffset] = speed * 16; + dsp_vptr->changed[salTimeOffset] |= 8; + dsp_vptr->lastUpdate.pitch = salTimeOffset; +} + +void hwSetSRCType(u32 v, u8 salSRCType) { + static u16 dspSRCType[3] = {0, 1, 2}; + struct DSPvoice* dsp_vptr = &dspVoice[v]; + dsp_vptr->srcTypeSelect = dspSRCType[salSRCType]; + dsp_vptr->changed[0] |= 0x100; +} + +void hwSetPolyPhaseFilter(unsigned long v, unsigned char salCoefSel) { + static u16 dspCoefSel[3] = {0, 1, 2}; + struct DSPvoice* dsp_vptr = &dspVoice[v]; + dsp_vptr->srcCoefSelect = dspCoefSel[salCoefSel]; + dsp_vptr->changed[0] |= 0x80; +} + +static void SetupITD(DSPvoice* dsp_vptr, u8 pan) { + dsp_vptr->itdShiftL = itdOffTab[pan]; + dsp_vptr->itdShiftR = 32 - itdOffTab[pan]; + dsp_vptr->changed[0] |= 0x200; +} + +void hwSetITDMode(u32 v, u8 mode) { + if (!mode) { + dspVoice[v].flags |= 0x80000000; + dspVoice[v].itdShiftL = 16; + dspVoice[v].itdShiftR = 16; + return; + } + dspVoice[v].flags &= ~0x80000000; +} + +#define hwGetITDMode(dsp_vptr) (dsp_vptr->flags & 0x80000000) + +void hwSetVolume(unsigned long v, unsigned char table, float vol, unsigned long pan, unsigned long span, float auxa, float auxb) { + SAL_VOLINFO vi; // r1+0x24 + unsigned short il; // r30 + unsigned short ir; // r29 + unsigned short is; // r28 + DSPvoice* dsp_vptr = &dspVoice[v]; // r31 + if (vol >= 1.f) { + vol = 1.f; + } + + if (auxa >= 1.f) { + auxa = 1.f; + } + + if (auxb >= 1.f) { + auxb = 1.f; + } + + salCalcVolume(table, &vi, vol, pan, span, auxa, auxb, (dsp_vptr->flags & 0x80000000) != 0, + dspStudio[dsp_vptr->studio].type == SND_STUDIO_TYPE_RESERVED0); + + il = 32767.f * vi.volL; + ir = 32767.f * vi.volR; + is = 32767.f * vi.volS; + + if (dsp_vptr->lastUpdate.vol == 0xff || dsp_vptr->volL != il || dsp_vptr->volR != ir || dsp_vptr->volS != is) { + dsp_vptr->volL = il; + dsp_vptr->volR = ir; + dsp_vptr->volS = is; + dsp_vptr->changed[0] |= 1; + dsp_vptr->lastUpdate.vol = 0; + } + + il = 32767.f * vi.volAuxAL; + ir = 32767.f * vi.volAuxAR; + is = 32767.f * vi.volAuxAS; + + if (dsp_vptr->lastUpdate.volA == 0xff || dsp_vptr->volLa != il || dsp_vptr->volRa != ir || dsp_vptr->volSa != is) { + dsp_vptr->volLa = il; + dsp_vptr->volRa = ir; + dsp_vptr->volSa = is; + dsp_vptr->changed[0] |= 2; + dsp_vptr->lastUpdate.volA = 0; + } + + il = 32767.f * vi.volAuxBL; + ir = 32767.f * vi.volAuxBR; + is = 32767.f * vi.volAuxBS; + + if (dsp_vptr->lastUpdate.volB == 0xff || dsp_vptr->volLb != il || dsp_vptr->volRb != ir || dsp_vptr->volSb != is) { + dsp_vptr->volLb = il; + dsp_vptr->volRb = ir; + dsp_vptr->volSb = is; + dsp_vptr->changed[0] |= 4; + dsp_vptr->lastUpdate.volB = 0; + } + + if (hwGetITDMode(dsp_vptr)) { + SetupITD(dsp_vptr, (pan >> 16)); + } +} + +void hwOff(s32 vid) { salDeactivateVoice(&dspVoice[vid]); } + +void hwSetAUXProcessingCallbacks(u8 studio, SND_AUX_CALLBACK auxA, void* userA, SND_AUX_CALLBACK auxB, void* userB) { + dspStudio[studio].auxAHandler = auxA; + dspStudio[studio].auxAUser = userA; + dspStudio[studio].auxBHandler = auxB; + dspStudio[studio].auxBUser = userB; +} + +void hwActivateStudio(unsigned char studio, unsigned long isMaster, SND_STUDIO_TYPE type) { salActivateStudio(studio, isMaster, type); } + +void hwDeactivateStudio(u8 studio) { salDeactivateStudio(studio); } + +void hwChangeStudioMix(u8 studio, u32 isMaster) { dspStudio[studio].isMaster = isMaster; } + +bool hwIsStudioActive(u8 studio) { return dspStudio[studio].state == 1; } + +bool hwAddInput(u8 studio, SND_STUDIO_INPUT* in_desc) { return salAddStudioInput(&dspStudio[studio], in_desc); } + +bool hwRemoveInput(u8 studio, SND_STUDIO_INPUT* in_desc) { return salRemoveStudioInput(&dspStudio[studio], in_desc); } + +void hwChangeStudio(u32 v, u8 studio) { salReconnectVoice(&dspVoice[v], studio); } + +u32 hwGetPos(u32 v) { + unsigned long pos; // r31 + unsigned long off; // r30 + if (dspVoice[v].state != 2) { + return 0; + } + + switch (dspVoice[v].smp_info.compType) { + case 0: + case 1: + case 4: + case 5: + pos = ((dspVoice[v].currentAddr - (u32)dspVoice[v].smp_info.addr * 2) / 16) * 14; + off = dspVoice[v].currentAddr & 0xf; + if (off >= 2) { + pos += off - 2; + } + break; + case 3: + pos = dspVoice[v].currentAddr - (u32)dspVoice[v].smp_info.addr; + break; + case 2: + pos = dspVoice[v].currentAddr - ((u32)dspVoice[v].smp_info.addr / 2); + break; + } + + return pos; +} + +void hwFlushStream(void* base, unsigned long offset, unsigned long bytes, unsigned char hwStreamHandle, void (*callback)(unsigned long), + unsigned long user) { + u32 aram; // r28 + u32 mram; // r29 + u32 len; + aram = aramGetStreamBufferAddress(hwStreamHandle, &len); + bytes += (offset & 31); + offset &= ~31; + bytes = (bytes + 31) & ~31; + mram = (u32)base + offset; + DCStoreRange((void*)mram, bytes); + aramUploadData((void*)mram, aram + offset, bytes, 1, callback, user); +} + +void hwPrepareStreamBuffer() {} +u8 hwInitStream(u32 len) { return aramAllocateStreamBuffer(len); } + +void hwExitStream(u8 id) { aramFreeStreamBuffer(id); } + +void* hwGetStreamPlayBuffer(u8 hwStreamHandle) { return (void*)aramGetStreamBufferAddress(hwStreamHandle, NULL); } + +void* hwTransAddr(void* samples) { return samples; } + +u32 hwFrq2Pitch(u32 frq) { return (frq * 4096.f) / synthInfo.mixFrq; } + +void hwInitSampleMem(u32 baseAddr, u32 length) { +#line 940 + MUSY_ASSERT(baseAddr==0x00000000); + aramInit(length); +} + +void hwExitSampleMem() { aramExit(); } + +static u32 convert_length(u32 len, u8 type) { + switch (type) { + case 0: + case 1: + case 4: + case 5: + return (((u32)((len + 0xD) / 0xe))) * 8; + case 2: + return len * 2; + } + return len; +} + +void hwSaveSample(void* header, void* data) { + u32 len = ((u32*)*((u32*)header))[1] & 0xFFFFFF; + u8 type = ((u32*)*((u32*)header))[1] >> 0x18; + len = convert_length(len, type); + *((u32*)data) = (u32)aramStoreData((void*)*((u32*)data), len); +} + +void hwSetSaveSampleCallback(ARAMUploadCallback callback, unsigned long chunckSize) { aramSetUploadCallback(callback, chunckSize); } + +void hwRemoveSample(void* header, void* data) { +#if MUSY_VERSION <= MUSY_VERSION_CHECK(1, 5, 3) + u32 len = (((u32*)header))[1] & 0xFFFFFF; + u8 type = (((u32*)header))[1] >> 0x18; + len = convert_length(len, type); +#else + u8 type = (((u32*)header))[1] >> 0x18; + u32 len = convert_length((((u32*)header))[1] & 0xFFFFFF, type); +#endif + aramRemoveData(data, len); +} + +void hwSyncSampleMem() { aramSyncTransferQueue(); } + +void hwFrameDone() {} + +void sndSetHooks(SND_HOOKS* hooks) { salHooks = *hooks; } + +void hwEnableHRTF() { + if (dspHRTFOn != FALSE) { + return; + } + dspHRTFOn = TRUE; + salInitHRTFBuffer(); +} +void hwDisableHRTF() { dspHRTFOn = FALSE; } + +u32 hwGetVirtualSampleID(u32 v) { + if (dspVoice[v].state == 0) { + return 0xFFFFFFFF; + } + + return dspVoice[v].virtualSampleID; +} + +bool hwVoiceInStartup(u32 v) { return dspVoice[v].state == 1; } diff --git a/src/musyx/runtime/dolphin/hw_aramdma.c b/src/musyx/runtime/dolphin/hw_aramdma.c new file mode 100644 index 00000000..6cc7eda7 --- /dev/null +++ b/src/musyx/runtime/dolphin/hw_aramdma.c @@ -0,0 +1,339 @@ +#include +#include +#include + +#include "musyx/assert.h" + +typedef struct ARAMTransferJob { + // total size: 0x28 + ARQRequest arq; // offset 0x0, size 0x20 + void (*callback)(unsigned long); // offset 0x20, size 0x4 + unsigned long user; // offset 0x24, size 0x4 +} ARAMTransferJob; + +typedef struct ARAMTransferQueue { + // total size: 0x284 + ARAMTransferJob queue[16]; // offset 0x0, size 0x280 + vu8 write; // offset 0x280, size 0x1 + vu8 valid; // offset 0x281, size 0x1 +} ARAMTransferQueue; + +typedef struct STREAM_BUFFER { + // total size: 0x10 + struct STREAM_BUFFER* next; // offset 0x0, size 0x4 + unsigned long aram; // offset 0x4, size 0x4 + unsigned long length; // offset 0x8, size 0x4 + unsigned long allocLength; // offset 0xC, size 0x4 +} STREAM_BUFFER; + +static unsigned long aramTop; // size: 0x4 +static unsigned long aramWrite; // size: 0x4 +static unsigned long aramStream; // size: 0x4 +static void* (*aramUploadCallback)(unsigned long, unsigned long); // size: 0x4 +static unsigned long aramUploadChunkSize; // size: 0x4 + +static ARAMTransferQueue aramQueueLo; +static ARAMTransferQueue aramQueueHi; + +static STREAM_BUFFER aramStreamBuffers[64]; +static STREAM_BUFFER* aramUsedStreamBuffers; +static STREAM_BUFFER* aramFreeStreamBuffers; +static STREAM_BUFFER* aramIdleStreamBuffers; + +static void InitStreamBuffers(); + +static void aramQueueInit() { + aramQueueLo.write = aramQueueLo.valid = 0; + aramQueueHi.write = aramQueueHi.valid = 0; +} + +static void aramQueueCallback(unsigned long ptr) { + u32 i; // r31 + ARQRequest* arq; // r29 + ARAMTransferQueue* aramQueue; // r30 + + arq = (ARQRequest*)ptr; + if (arq->priority == 1) { + aramQueue = &aramQueueHi; + } else { + aramQueue = &aramQueueLo; + } + + for (i = 0; i < 16; ++i) { + if (arq == &aramQueue->queue[i].arq && aramQueue->queue[i].callback) { + aramQueue->queue[i].callback(aramQueue->queue[i].user); + } + } + + --aramQueue->valid; +} + +void aramUploadData(void* mram, unsigned long aram, unsigned long len, unsigned long highPrio, + void (*callback)(unsigned long), unsigned long user) { + ARAMTransferQueue* aramQueue; // r31 + int old; // r30 + + aramQueue = highPrio != 0 ? &aramQueueHi : &aramQueueLo; + + for (;;) { + old = OSDisableInterrupts(); + if (aramQueue->valid < 16) { + aramQueue->queue[aramQueue->write].arq.owner = 42; + aramQueue->queue[aramQueue->write].arq.type = 0; + aramQueue->queue[aramQueue->write].arq.priority = highPrio != 0 ? 1 : 0; + aramQueue->queue[aramQueue->write].arq.source = (u32)mram; + aramQueue->queue[aramQueue->write].arq.dest = aram; + aramQueue->queue[aramQueue->write].arq.length = len; + aramQueue->queue[aramQueue->write].arq.callback = aramQueueCallback; + aramQueue->queue[aramQueue->write].callback = callback; + aramQueue->queue[aramQueue->write].user = user; + ARQPostRequest(&aramQueue->queue[aramQueue->write].arq, + aramQueue->queue[aramQueue->write].arq.owner, + aramQueue->queue[aramQueue->write].arq.type, + aramQueue->queue[aramQueue->write].arq.priority, + aramQueue->queue[aramQueue->write].arq.source, + aramQueue->queue[aramQueue->write].arq.dest, + aramQueue->queue[aramQueue->write].arq.length, + aramQueue->queue[aramQueue->write].arq.callback); + ++aramQueue->valid; + aramQueue->write = (aramQueue->write + 1) % 16; + OSRestoreInterrupts(old); + return; + } + OSRestoreInterrupts(old); + } +} + +void aramSyncTransferQueue() { + while (aramQueueLo.valid != 0) { + } +} + +void aramInit(unsigned long length) { + signed short* tmpMem; // r30 + unsigned long i; // r29 + unsigned long aramBase; // r28 +#line 173 + MUSY_ASSERT_MSG(length > sizeof(s16) * 640, "ARAM size is too small"); + + aramBase = ARGetBaseAddress(); + + tmpMem = (s16*)salMalloc(sizeof(s16) * 640); +#line 182 + MUSY_ASSERT_MSG(tmpMem != NULL, "Could not allocate temporary storage"); + + for (i = 0; i < 640; ++i) { + tmpMem[i] = 0; + } + + DCFlushRange(tmpMem, sizeof(s16) * 640); + aramQueueInit(); + aramUploadData(tmpMem, aramBase, sizeof(s16) * 640, 0, NULL, 0); + aramSyncTransferQueue(); + salFree(tmpMem); + aramTop = aramBase + length; + if (aramTop > ARGetSize()) { + aramTop = ARGetSize(); + } + + aramWrite = aramBase + sizeof(s16) * 640; + aramUploadCallback = NULL; + InitStreamBuffers(); + MUSY_DEBUG("MusyX ARAM handler initialized\n"); +} + +void aramExit() {} + +unsigned long aramGetZeroBuffer() { return ARGetBaseAddress(); } + +void aramSetUploadCallback(void* (*callback)(unsigned long, unsigned long), + unsigned long chunckSize) { + unsigned long acs; // r30 + + if (callback != NULL) { + chunckSize = (chunckSize + 31) & ~31; + acs = ARQGetChunkSize(); + aramUploadChunkSize = chunckSize < acs ? acs : chunckSize; + } + + aramUploadCallback = callback; +} + +void* aramStoreData(void* src, unsigned long len) { + unsigned long addr; // r26 + void* buffer; // r27 + unsigned long blkSize; // r30 + len = (len + 31) & ~31; +#line 266 + MUSY_ASSERT_MSG(aramWrite + len <= aramStream, "Data will not fit in remaining ARAM space"); + addr = aramWrite; + if (aramUploadCallback == NULL) { +#line 276 + MUSY_ASSERT_MSG(!((u32)src & 31), "MRAM address is not aligned properly"); + DCFlushRange(src, len); + aramUploadData(src, aramWrite, len, 0, NULL, 0); + aramWrite += len; + return (void*)addr; + } + + while (len != 0) { + blkSize = len >= aramUploadChunkSize ? aramUploadChunkSize : len; + buffer = (void*)aramUploadCallback((u32)src, blkSize); +#line 297 + MUSY_ASSERT_MSG(!((u32)buffer & 31), "MRAM address is not aligned properly"); + DCFlushRange(buffer, blkSize); + aramUploadData(buffer, aramWrite, blkSize, 0, NULL, 0); + len -= blkSize; + aramWrite += blkSize; + src = (void*)((u32)src + blkSize); + } + + return (void*)addr; +} + +void aramRemoveData(void* aram, unsigned long len) { + len = (len + 31) & ~31; + aramWrite -= len; +#line 328 + MUSY_ASSERT_MSG((u32)aram == aramWrite, + "Current ARAM address does not match originally allocated one"); +} + +static void InitStreamBuffers() { + unsigned long i; // r31 + aramUsedStreamBuffers = NULL; + aramFreeStreamBuffers = NULL; + aramIdleStreamBuffers = aramStreamBuffers; + for (i = 1; i < 64; ++i) { + aramStreamBuffers[i - 1].next = &aramStreamBuffers[i]; + } + aramStreamBuffers[i - 1].next = NULL; + aramStream = aramTop; +} + +unsigned char aramAllocateStreamBuffer(unsigned long len) { + STREAM_BUFFER* sb; // r30 + STREAM_BUFFER* oSb; // r31 + STREAM_BUFFER* lastSb; // r28 + u32 minLen; // r27 + + len = (len + 31) & ~31; + lastSb = oSb = NULL; + minLen = -1; + + for (sb = aramFreeStreamBuffers; sb != NULL; sb = sb->next) { + if (sb->allocLength == len) { + oSb = sb; + break; + } + + if (sb->allocLength > len && minLen > sb->allocLength) { + oSb = sb; + minLen = sb->allocLength; + } + lastSb = sb; + } + + if (oSb == NULL) { + if (aramIdleStreamBuffers != NULL && aramStream - len >= aramWrite) { + oSb = aramIdleStreamBuffers; + aramIdleStreamBuffers = oSb->next; + oSb->allocLength = len; + oSb->length = len; + aramStream -= len; + oSb->aram = aramStream; + oSb->next = aramUsedStreamBuffers; + aramUsedStreamBuffers = oSb; + } + } else { + if (lastSb != NULL) { + lastSb->next = oSb->next; + } else { + aramFreeStreamBuffers = oSb->next; + } + + oSb->length = len; + oSb->next = aramUsedStreamBuffers; + aramUsedStreamBuffers = oSb; + } + + if (oSb == NULL) { + MUSY_DEBUG("No stream buffer slots available or ARAM.\n\n"); + return 0xFF; + } + + return (oSb - aramStreamBuffers); +} + +unsigned long aramGetStreamBufferAddress(unsigned char id, unsigned long* len) { +#line 467 + MUSY_ASSERT_MSG(id != 0xFF, "Stream buffer ID is invalid"); + + if (len != NULL) { + *len = aramStreamBuffers[id].length; + } + + return aramStreamBuffers[id].aram; +} + +void aramFreeStreamBuffer(unsigned char id) { + struct STREAM_BUFFER* fSb; // r30 + struct STREAM_BUFFER* sb; // r31 + struct STREAM_BUFFER* lastSb; // r29 + struct STREAM_BUFFER* nextSb; // r27 + unsigned long minAddr; // r28 + + MUSY_ASSERT_MSG(id != 0xFF, "Stream buffer ID is invalid"); + fSb = &aramStreamBuffers[id]; + lastSb = NULL; + sb = aramUsedStreamBuffers; + + while (sb != NULL) { + if (sb == fSb) { + if (lastSb != NULL) { + lastSb->next = fSb->next; + } else { + aramUsedStreamBuffers = fSb->next; + } + break; + } else { + lastSb = sb; + sb = sb->next; + } + } + + if (fSb->aram == aramStream) { + fSb->next = aramIdleStreamBuffers; + aramIdleStreamBuffers = fSb; + minAddr = -1; + sb = aramUsedStreamBuffers; + while (sb != NULL) { + if (sb->aram <= minAddr) { + minAddr = sb->aram; + } + sb = sb->next; + } + + lastSb = NULL; + sb = aramFreeStreamBuffers; + while (sb != NULL) { + nextSb = sb->next; + if (sb->aram < minAddr) { + if (lastSb != NULL) { + lastSb->next = sb->next; + } else { + aramFreeStreamBuffers = sb->next; + } + + sb->next = aramIdleStreamBuffers; + aramIdleStreamBuffers = sb; + } + sb = nextSb; + } + + aramStream = minAddr != -1 ? minAddr : aramTop; + return; + } + fSb->next = aramFreeStreamBuffers; + aramFreeStreamBuffers = fSb; +} diff --git a/src/musyx/runtime/dolphin/hw_dolphin.c b/src/musyx/runtime/dolphin/hw_dolphin.c new file mode 100644 index 00000000..4f6a9325 --- /dev/null +++ b/src/musyx/runtime/dolphin/hw_dolphin.c @@ -0,0 +1,171 @@ +#include "dolphin/dsp.h" +#include "musyx/assert.h" +#include "musyx/dsp_import.h" +#include "musyx/hardware.h" +#include "musyx/sal.h" + +static DSPTaskInfo dsp_task ATTRIBUTE_ALIGN(8); +static u16 dram_image[4096] ATTRIBUTE_ALIGN(32); + +static volatile u32 oldState = 0; +static volatile u16 hwIrqLevel = 0; +static volatile u32 salDspInitIsDone = 0; +static volatile OSTick salLastTick = 0; +static volatile u32 salLogicActive = 0; +static volatile u32 salLogicIsWaiting = 0; +static volatile u32 salDspIsDone = 0; +void* salAIBufferBase = NULL; +static u8 salAIBufferIndex = 0; +static SND_SOME_CALLBACK userCallback = NULL; + +#define DMA_BUFFER_LEN 0x280 + +u32 salGetStartDelay(); +static void callUserCallback() { + if (salLogicActive) { + return; + } + salLogicActive = 1; + OSEnableInterrupts(); + userCallback(); + OSDisableInterrupts(); + salLogicActive = 0; +} + +void salCallback() { + salAIBufferIndex = (salAIBufferIndex + 1) % 4; + AIInitDMA(OSCachedToPhysical(salAIBufferBase) + (salAIBufferIndex * DMA_BUFFER_LEN), + DMA_BUFFER_LEN); + salLastTick = OSGetTick(); + if (salDspIsDone) { + callUserCallback(); + } else { + salLogicIsWaiting = 1; + } +} + +void dspInitCallback() { + salDspIsDone = TRUE; + salDspInitIsDone = TRUE; +} + +void dspResumeCallback() { + salDspIsDone = TRUE; + if (salLogicIsWaiting) { + salLogicIsWaiting = FALSE; + callUserCallback(); + } +} + +u32 salInitAi(SND_SOME_CALLBACK callback, u32 unk, u32* outFreq) { + if ((salAIBufferBase = salMalloc(DMA_BUFFER_LEN * 4)) != NULL) { + memset(salAIBufferBase, 0, DMA_BUFFER_LEN * 4); + DCFlushRange(salAIBufferBase, DMA_BUFFER_LEN * 4); + salAIBufferIndex = TRUE; + salLogicIsWaiting = FALSE; + salDspIsDone = TRUE; + salLogicActive = FALSE; + userCallback = callback; + AIRegisterDMACallback(salCallback); + AIInitDMA(OSCachedToPhysical(salAIBufferBase) + (salAIBufferIndex * 0x280), 0x280); + synthInfo.numSamples = 0x20; + *outFreq = 32000; + MUSY_DEBUG("MusyX AI interface initialized.\n"); + return TRUE; + } + + return FALSE; +} + +u32 salStartAi() { AIStartDMA(); } + +u32 salExitAi() { + AIRegisterDMACallback(NULL); + AIStopDMA(); + salFree(salAIBufferBase); + return TRUE; +} + +void* salAiGetDest() { + u8 index; // r31 + index = (salAIBufferIndex + 2) % 4; + return (void*)((u8*)salAIBufferBase + index * DMA_BUFFER_LEN); +} + +u32 salInitDsp() { + u8 _[8]; + dsp_task.iram_mmem_addr = (u16*)dspSlave; + dsp_task.iram_length = dspSlaveLength; + dsp_task.iram_addr = 0; + dsp_task.dram_mmem_addr = (u16*)dram_image; + dsp_task.dram_length = 0x2000; + dsp_task.dram_addr = 0; + dsp_task.dsp_init_vector = 0x10; + dsp_task.dsp_resume_vector = 0x30; + dsp_task.init_cb = dspInitCallback; + dsp_task.res_cb = dspResumeCallback; + dsp_task.done_cb = NULL; + dsp_task.req_cb = NULL; + dsp_task.priority = 0; + DSPInit(); + DSPAddTask(&dsp_task); + salDspInitIsDone = FALSE; + hwEnableIrq(); + while (!salDspInitIsDone) + ; + hwDisableIrq(); + return TRUE; +} + +u32 salExitDsp() { + DSPHalt(); + while (DSPGetDMAStatus()) + ; + DSPReset(); + + return TRUE; +} +void salStartDsp(u16* cmdList) { + salDspIsDone = FALSE; + PPCSync(); + /* clang-format off */ + MUSY_ASSERT(((u32)cmdList&0x1F) == 0); + /* clang-format on */ + DSPSendMailToDSP(dspCmdFirstSize | 0xbabe0000); + + while (DSPCheckMailToDSP()) + ; + DSPSendMailToDSP((u32)cmdList); + while (DSPCheckMailToDSP()) + ; +} + +void salCtrlDsp(u32 unk) { + salBuildCommandList(unk, salGetStartDelay()); + salStartDsp(dspCmdList); +} + +u32 salGetStartDelay() { return OSTicksToMicroseconds(OSGetTick() - salLastTick); } + +void hwInitIrq() { + oldState = OSDisableInterrupts(); + hwIrqLevel = 1; +} + +void hwExitIrq() {} + +void hwEnableIrq() { + if (--hwIrqLevel == 0) { + OSRestoreInterrupts(oldState); + } +} + +void hwDisableIrq() { + if ((hwIrqLevel++) == 0) { + oldState = OSDisableInterrupts(); + } +} + +void hwIRQEnterCritical() { OSDisableInterrupts(); } + +void hwIRQLeaveCritical() { OSEnableInterrupts(); } diff --git a/src/musyx/runtime/dolphin/profile.c b/src/musyx/runtime/dolphin/profile.c new file mode 100644 index 00000000..53000f0e --- /dev/null +++ b/src/musyx/runtime/dolphin/profile.c @@ -0,0 +1,94 @@ +#include "dolphin/PPCArch.h" +#include "musyx/musyx_priv.h" + +SND_PROF_USERCALLBACK sndProfUserCallback = NULL; + +void sndProfSetCallback(SND_PROF_USERCALLBACK callback) { sndProfUserCallback = callback; } + +void sndProfUpdateMisc(SND_PROFILE_INFO* info) { + info->numMusicVoices = voiceMusicRunning; + info->numSFXVoices = voiceFxRunning; +} + +void sndProfResetPMC(SND_PROFILE_DATA* info) { + PPCMtpmc1(0); + PPCMtpmc2(0); + PPCMtpmc3(0); + PPCMtpmc4(0); + info->sumLoadStores = info->loadStores = 0; + info->sumMissCycles = info->missCycles = 0; + info->sumCycles = info->cycles = 0; + info->sumInstructions = info->instructions = 0; + info->peekLoadStores = 0; + info->peekMissCycles = 0; + info->peekCycles = 0; + info->peekInstructions = 0; + info->cnt = 0; + info->paused = 1; +} +void sndProfStartPMC(SND_PROFILE_DATA* info) { + PPCMtmmcr0(0); + PPCMtmmcr1(0); + info->paused = 0; + info->_loadStores = PPCMfpmc2(); + info->_missCycles = PPCMfpmc3(); + info->_cycles = PPCMfpmc4(); + info->_instructions = PPCMfpmc1(); + PPCMtmmcr1(0x78400000); + PPCMtmmcr0(0xc08b); +} + +void sndProfPausePMC(SND_PROFILE_DATA* info) { + PPCMtmmcr0(0); + PPCMtmmcr1(0); + info->loadStores += PPCMfpmc2() - info->_loadStores; + info->missCycles += PPCMfpmc3() - info->_missCycles; + info->cycles += PPCMfpmc4() - info->_cycles; + info->instructions += PPCMfpmc1() - info->_instructions; + info->paused = 1; + PPCMtmmcr1(0x78400000); + PPCMtmmcr0(0xc08b); +} +void sndProfStopPMC(SND_PROFILE_DATA* info) { + PPCMtmmcr0(0); + PPCMtmmcr1(0); + if (info->paused == 0) { + info->loadStores = info->loadStores + (PPCMfpmc2() - info->_loadStores); + info->missCycles = info->missCycles + (PPCMfpmc3() - info->_missCycles); + info->cycles = info->cycles + (PPCMfpmc4() - info->_cycles); + info->instructions = info->instructions + (PPCMfpmc1() - info->_instructions); + info->paused = 1; + } + info->cnt = info->cnt + 1; + info->sumLoadStores += info->loadStores; + info->sumMissCycles += info->missCycles; + + info->sumCycles += info->cycles; + info->sumInstructions += info->instructions; + info->avgLoadStores = info->sumLoadStores / info->cnt; + info->avgMissCycles = info->sumMissCycles / info->cnt; + info->avgCycles = info->sumCycles / info->cnt; + info->avgInstructions = info->sumInstructions / info->cnt; + info->lastLoadStores = info->loadStores; + info->lastMissCycles = info->missCycles; + info->lastCycles = info->cycles; + info->lastInstructions = info->instructions; + if (info->loadStores > info->peekLoadStores) { + info->peekLoadStores = info->loadStores; + } + if (info->missCycles > info->peekMissCycles) { + info->peekMissCycles = info->missCycles; + } + if (info->cycles > info->peekCycles) { + info->peekCycles = info->cycles; + } + if (info->instructions > info->peekInstructions) { + info->peekInstructions = info->instructions; + } + info->loadStores = 0; + info->missCycles = 0; + info->cycles = 0; + info->instructions = 0; + PPCMtmmcr1(0x78400000); + PPCMtmmcr0(0xc08b); +}