Various fixes and matches

This commit is contained in:
Phillip Stephens 2023-03-29 19:27:34 -07:00
parent a5c3f5a97c
commit f75b37e773
23 changed files with 2120 additions and 478 deletions

View File

@ -3,8 +3,8 @@
{
"name": "Linux",
"includePath": [
"${workspaceFolder}/include",
"${workspaceFolder}/libc"
"${workspaceFolder}/include/**",
"${workspaceFolder}/libc/**"
],
"cStandard": "c99",
"cppStandard": "c++98",

View File

@ -59,7 +59,8 @@
"osfont.h": "c",
"arq.h": "c",
"string.h": "c",
"hw_regs.h": "c"
"hw_regs.h": "c",
"synth.h": "c"
},
"files.autoSave": "onFocusChange",
"files.insertFinalNewline": true,

View File

@ -925,7 +925,7 @@ LIBS = [
"cflags": "$cflags_musyx -DMUSY_VERSION_MAJOR=1 -DMUSY_VERSION_MINOR=5 -DMUSY_VERSION_PATCH=4",
"host": False,
"objects": [
"musyx/runtime/seq",
["musyx/runtime/seq", False],
["musyx/runtime/synth", False],
["musyx/runtime/seq_api", True],
["musyx/runtime/snd_synthapi", True, {"add_to_all": False}],
@ -1034,6 +1034,7 @@ LIBS = [
{
"lib": "gba",
"mw_version": "1.2.5e",
#"cflags" : "-proc gecko -Cpp_exceptions off -fp hard -nodefaults -nosyspath -i include -i libc -g -sym on -D_DEBUG=1 -enum int -use_lmw_stmw on",
"cflags": "$cflags_base",
"host": False,
"objects": [
@ -1043,7 +1044,7 @@ LIBS = [
["Dolphin/GBA/GBARead", True],
["Dolphin/GBA/GBAWrite", True],
["Dolphin/GBA/GBAXfer", True],
"Dolphin/GBA/GBAKey",
["Dolphin/GBA/GBAKey", True],
],
},
]

View File

@ -13,7 +13,7 @@ extern "C" {
typedef void (*GBATransferCallback)(s32 chan);
typedef struct GBASecParams {
typedef struct GBASecParam {
u8 readbuf[4];
s32 paletteColor;
s32 paletteSpeed;
@ -23,7 +23,7 @@ typedef struct GBASecParams {
u32 keyA;
s32 keyB;
u8 _padding1[24];
} GBASecParams;
} GBASecParam;
typedef struct GBABootInfo {
s32 paletteColor;
@ -61,7 +61,7 @@ typedef struct GBAControl {
GBATransferCallback proc;
GBABootInfo bootInfo;
DSPTaskInfo task;
GBASecParams* param;
GBASecParam* param;
} GBAControl;
extern GBAControl __GBA[4];

View File

@ -29,12 +29,21 @@ u32 __OSCoreClock AT_ADDRESS(OS_BASE_CACHED | 0x00FC); // sync with OSLoMem.h
#define OS_CORE_CLOCK __OSCoreClock
#define OS_TIMER_CLOCK (OS_BUS_CLOCK / 4)
#ifndef _DEBUG
#define OSPhysicalToCached(paddr) ((void*)((u32)(paddr) + OS_BASE_CACHED))
#define OSPhysicalToUncached(paddr) ((void*)((u32)(paddr) + OS_BASE_UNCACHED))
#define OSCachedToPhysical(caddr) ((u32)((u8*)(caddr)-OS_BASE_CACHED))
#define OSUncachedToPhysical(ucaddr) ((u32)((u8*)(ucaddr)-OS_BASE_UNCACHED))
#define OSCachedToUncached(caddr) ((void*)((u8*)(caddr) + (OS_BASE_UNCACHED - OS_BASE_CACHED)))
#define OSUncachedToCached(ucaddr) ((void*)((u8*)(ucaddr) - (OS_BASE_UNCACHED - OS_BASE_CACHED)))
#else
u32 OSPhysicalToCached(void* paddr);
u32 OSPhysicalToUncached(void* paddr);
u32 OSCachedToPhysical(void* caddr);
u32 OSUncachedToPhysical(void* ucaddr);
u32 OSCachedToUncached(void* caddr);
u32 OSUncachedToCached(void* ucaddr);
#endif
#define OSTicksToCycles(ticks) (((ticks) * ((OS_CORE_CLOCK * 2) / OS_TIMER_CLOCK)) / 2)
#define OSTicksToSeconds(ticks) ((ticks) / OS_TIMER_CLOCK)

View File

@ -1,20 +1,15 @@
#ifndef _MUSYX_ASSERT
#define _MUSYX_ASSERT
#include "musyx/version.h"
extern void OSPanic(const char* file, int line, const char* msg, ...);
extern void OSReport(const char* msg, ...);
static inline unsigned __SOME_ASSERT_DERP1() {
return 0;
}
static inline unsigned __SOME_ASSERT_DERP1() { return 0; }
static inline unsigned __SOME_ASSERT_DERP2() {
return __SOME_ASSERT_DERP1();
}
static inline unsigned __SOME_ASSERT_DERP2() { return __SOME_ASSERT_DERP1(); }
static inline void __SOME_ASSERT_DERP() {
__SOME_ASSERT_DERP2() != 0;
}
static inline void __SOME_ASSERT_DERP() { __SOME_ASSERT_DERP2() != 0; }
#ifndef ASSERT
#ifdef _DEBUG
@ -24,7 +19,7 @@ static inline void __SOME_ASSERT_DERP() {
OSPanic(__FILE__, __LINE__, "Failed assertion " #cond); \
} \
__SOME_ASSERT_DERP(); \
} while(0)
} while (0)
#else
#define MUSY_ASSERT(cond)
#endif
@ -32,12 +27,27 @@ static inline void __SOME_ASSERT_DERP() {
#ifndef MUSY_ASSERT_MSG
#ifdef _DEBUG
#if MUSY_VERSION >= MUSY_VERSION_CHECK(2, 0, 0)
#define MUSY_ASSERT_MSG(cond, msg) \
do { \
s32 tmp = 1; \
s32 tmp2; \
if (!(cond)) { \
OSPanic(__FILE__, __LINE__, msg); \
tmp2 = 0; \
if (tmp2 == 0) { \
tmp = 0; \
} \
} \
} while (0)
#else
#define MUSY_ASSERT_MSG(cond, msg) \
do { \
if (!(cond)) { \
OSPanic(__FILE__, __LINE__, msg); \
} \
} while(0)
} while (0)
#endif
#else
#define MUSY_ASSERT_MSG(cond, msg)
#endif
@ -51,4 +61,12 @@ static inline void __SOME_ASSERT_DERP() {
#endif
#endif
#ifndef MUSY_FATAL
#ifdef _DEBUG
#define MUSY_FATAL(msg) OSPanic(__FILE__, __LINE__, msg)
#else
#define MUSY_FATAL
#endif
#endif
#endif // _MUSYX_ASSERT

View File

@ -39,6 +39,10 @@ typedef signed long bool;
#define SYNTH_MAX_VOICES 64
typedef struct SND_ADPCMSTREAM_INFO {
s16 coefTab[8][2]; // Table of coef. pairs
} SND_ADPCMSTREAM_INFO;
typedef u32 SND_SEQID;
typedef u32 SND_VOICEID;
typedef u32 SND_STREAMID;
@ -65,6 +69,13 @@ typedef struct SND_SEQVOLDEF {
u8 volGroup;
} SND_SEQVOLDEF;
#define SND_PLAYPARA_DEFAULT 0x00000000
#define SND_PLAYPARA_TRACKMUTE 0x00000001
#define SND_PLAYPARA_SPEED 0x00000002
#define SND_PLAYPARA_VOLUME 0x00000004
#define SND_PLAYPARA_SEQVOLDEF 0x00000008
#define SND_PLAYPARA_PAUSE 0x00000010
typedef struct SND_PLAYPARA {
u32 flags;
u32 trackMute[2];
@ -310,6 +321,37 @@ bool sndAuxCallbackPrepareChorus(SND_AUX_CHORUS* ch);
bool sndAuxCallbackShutdownChorus(SND_AUX_CHORUS* ch);
bool sndAuxCallbackUpdateSettingsChorus(SND_AUX_CHORUS* ch);
#define SND_CROSSFADE_STOP 0 // Stop old song after fadedown
#define SND_CROSSFADE_PAUSE 1 // Pause old song after fadedown
#define SND_CROSSFADE_CONTINUE 2 // Continue previously paused song as new one
#define SND_CROSSFADE_START 0 // Start new song (no continue)
#define SND_CROSSFADE_SYNC 4 // Crossfade should start syncronized by sync-controller (104)
#define SND_CROSSFADE_PAUSENEW 8 // Pause new song before even starting it
#define SND_CROSSFADE_TRACKMUTE 16 // Use trackmute informtion
#define SND_CROSSFADE_SPEED 32 // Use speed informtion
#define SND_CROSSFADE_MUTE 64 // Old song continues playing & gets muted after fade down
#define SND_CROSSFADE_MUTENEW 128 // Mute new song after starting it
#define SND_CROSSFADE_DEFAULT 0
typedef struct SND_CROSSFADE {
SND_SEQID seqId1;
u16 time1;
SND_SEQID seqId2;
u16 time2;
void* arr2;
SND_GROUPID gid2;
SND_SONGID sid2;
u8 vol2;
u8 studio2;
u32 trackMute2[2];
u16 speed2;
u8 flags;
} SND_CROSSFADE;
typedef struct SND_PROFILE_DATA {
unsigned long loadStores;
unsigned long missCycles;

View File

@ -10,10 +10,10 @@ extern "C" {
typedef struct SND_STUDIO_INPUT {
// total size: 0x4
unsigned char vol; // offset 0x0, size 0x1
unsigned char volA; // offset 0x1, size 0x1
unsigned char volB; // offset 0x2, size 0x1
unsigned char srcStudio; // offset 0x3, size 0x1
u8 vol; // offset 0x0, size 0x1
u8 volA; // offset 0x1, size 0x1
u8 volB; // offset 0x2, size 0x1
u8 srcStudio; // offset 0x3, size 0x1
} SND_STUDIO_INPUT;
typedef struct SYNTH_VOICELIST {
@ -28,8 +28,8 @@ extern SYNTH_VOICELIST voicePrioSortVoices[64];
typedef struct SYNTH_ROOTLIST {
// total size: 0x4
unsigned short next; // offset 0x0, size 0x2
unsigned short prev; // offset 0x2, size 0x2
u16 next; // offset 0x0, size 0x2
u16 prev; // offset 0x2, size 0x2
} SYNTH_ROOTLIST;
extern SYNTH_ROOTLIST voicePrioSortRootList[256];
@ -73,117 +73,117 @@ typedef struct ADSR_VARS {
typedef struct _PBMIX {
// total size: 0x24
unsigned short vL; // offset 0x0, size 0x2
unsigned short vDeltaL; // offset 0x2, size 0x2
unsigned short vR; // offset 0x4, size 0x2
unsigned short vDeltaR; // offset 0x6, size 0x2
unsigned short vAuxAL; // offset 0x8, size 0x2
unsigned short vDeltaAuxAL; // offset 0xA, size 0x2
unsigned short vAuxAR; // offset 0xC, size 0x2
unsigned short vDeltaAuxAR; // offset 0xE, size 0x2
unsigned short vAuxBL; // offset 0x10, size 0x2
unsigned short vDeltaAuxBL; // offset 0x12, size 0x2
unsigned short vAuxBR; // offset 0x14, size 0x2
unsigned short vDeltaAuxBR; // offset 0x16, size 0x2
unsigned short vAuxBS; // offset 0x18, size 0x2
unsigned short vDeltaAuxBS; // offset 0x1A, size 0x2
unsigned short vS; // offset 0x1C, size 0x2
unsigned short vDeltaS; // offset 0x1E, size 0x2
unsigned short vAuxAS; // offset 0x20, size 0x2
unsigned short vDeltaAuxAS; // offset 0x22, size 0x2
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
unsigned short flag; // offset 0x0, size 0x2
unsigned short bufferHi; // offset 0x2, size 0x2
unsigned short bufferLo; // offset 0x4, size 0x2
unsigned short shiftL; // offset 0x6, size 0x2
unsigned short shiftR; // offset 0x8, size 0x2
unsigned short targetShiftL; // offset 0xA, size 0x2
unsigned short targetShiftR; // offset 0xC, size 0x2
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
unsigned short updNum[5]; // offset 0x0, size 0xA
unsigned short dataHi; // offset 0xA, size 0x2
unsigned short dataLo; // offset 0xC, size 0x2
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
unsigned short aL; // offset 0x0, size 0x2
unsigned short aAuxAL; // offset 0x2, size 0x2
unsigned short aAuxBL; // offset 0x4, size 0x2
unsigned short aR; // offset 0x6, size 0x2
unsigned short aAuxAR; // offset 0x8, size 0x2
unsigned short aAuxBR; // offset 0xA, size 0x2
unsigned short aS; // offset 0xC, size 0x2
unsigned short aAuxAS; // offset 0xE, size 0x2
unsigned short aAuxBS; // offset 0x10, size 0x2
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
unsigned short currentVolume; // offset 0x0, size 0x2
unsigned short currentDelta; // offset 0x2, size 0x2
u16 currentVolume; // offset 0x0, size 0x2
u16 currentDelta; // offset 0x2, size 0x2
} _PBVE;
typedef struct _PBFIR {
// total size: 0x6
unsigned short numCoefs; // offset 0x0, size 0x2
unsigned short coefsHi; // offset 0x2, size 0x2
unsigned short coefsLo; // offset 0x4, size 0x2
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
unsigned short loopFlag; // offset 0x0, size 0x2
unsigned short format; // offset 0x2, size 0x2
unsigned short loopAddressHi; // offset 0x4, size 0x2
unsigned short loopAddressLo; // offset 0x6, size 0x2
unsigned short endAddressHi; // offset 0x8, size 0x2
unsigned short endAddressLo; // offset 0xA, size 0x2
unsigned short currentAddressHi; // offset 0xC, size 0x2
unsigned short currentAddressLo; // offset 0xE, size 0x2
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
unsigned short a[8][2]; // offset 0x0, size 0x20
unsigned short gain; // offset 0x20, size 0x2
unsigned short pred_scale; // offset 0x22, size 0x2
unsigned short yn1; // offset 0x24, size 0x2
unsigned short yn2; // offset 0x26, size 0x2
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
} _PDADPCM;
typedef struct _PBSRC {
// total size: 0xE
unsigned short ratioHi; // offset 0x0, size 0x2
unsigned short ratioLo; // offset 0x2, size 0x2
unsigned short currentAddressFrac; // offset 0x4, size 0x2
unsigned short last_samples[4]; // offset 0x6, size 0x8
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
unsigned short loop_pred_scale; // offset 0x0, size 0x2
unsigned short loop_yn1; // offset 0x2, size 0x2
unsigned short loop_yn2; // offset 0x4, size 0x2
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
unsigned short nextHi; // offset 0x0, size 0x2
unsigned short nextLo; // offset 0x2, size 0x2
unsigned short currHi; // offset 0x4, size 0x2
unsigned short currLo; // offset 0x6, size 0x2
unsigned short srcSelect; // offset 0x8, size 0x2
unsigned short coefSelect; // offset 0xA, size 0x2
unsigned short mixerCtrl; // offset 0xC, size 0x2
unsigned short state; // offset 0xE, size 0x2
unsigned short loopType; // offset 0x10, size 0x2
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
struct _PBMIX mix; // offset 0x12, size 0x24
struct _PBITD itd; // offset 0x36, size 0xE
struct _PBUPDATE update; // offset 0x44, size 0xE
@ -194,7 +194,7 @@ typedef struct _PB {
struct _PBADPCM adpcm; // offset 0x7E, size 0x28
struct _PBSRC src; // offset 0xA6, size 0xE
struct _PBADPCMLOOP adpcmLoop; // offset 0xB4, size 0x6
unsigned short streamLoopCnt; // offset 0xBA, size 0x2
u16 streamLoopCnt; // offset 0xBA, size 0x2
} _PB;
typedef struct SAMPLE_INFO {
@ -211,81 +211,81 @@ typedef struct SAMPLE_INFO {
typedef struct GROUP_DATA {
// total size: 0x28
unsigned long nextOff; // offset 0x0, size 0x4
unsigned short id; // offset 0x4, size 0x2
unsigned short type; // offset 0x6, size 0x2
unsigned long macroOff; // offset 0x8, size 0x4
unsigned long sampleOff; // offset 0xC, size 0x4
unsigned long curveOff; // offset 0x10, size 0x4
unsigned long keymapOff; // offset 0x14, size 0x4
unsigned long layerOff; // offset 0x18, size 0x4
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
unsigned long tableOff; // offset 0x0, size 0x4
u32 tableOff; // offset 0x0, size 0x4
} fx;
struct song {
// total size: 0xC
unsigned long normpageOff; // offset 0x0, size 0x4
unsigned long drumpageOff; // offset 0x4, size 0x4
unsigned long midiSetupOff; // offset 0x8, size 0x4
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
unsigned long info; // offset 0x0, size 0x4
unsigned long length; // offset 0x4, size 0x4
unsigned long loopOffset; // offset 0x8, size 0x4
unsigned long loopLength; // offset 0xC, size 0x4
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
unsigned short id; // offset 0x0, size 0x2
unsigned short ref_cnt; // offset 0x2, size 0x2
unsigned long offset; // offset 0x4, size 0x4
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
struct SAMPLE_HEADER header; // offset 0xC, size 0x10
unsigned long extraData; // offset 0x1C, size 0x4
u32 extraData; // offset 0x1C, size 0x4
} SDIR_DATA;
typedef struct SDIR_TAB {
// total size: 0xC
struct SDIR_DATA* data; // offset 0x0, size 0x4
void* base; // offset 0x4, size 0x4
unsigned short numSmp; // offset 0x8, size 0x2
unsigned short res; // offset 0xA, size 0x2
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
unsigned short id; // offset 0x4, size 0x2
unsigned short refCount; // offset 0x6, size 0x2
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
unsigned short id; // offset 0x4, size 0x2
unsigned short num; // offset 0x6, size 0x2
unsigned short refCount; // offset 0x8, size 0x2
unsigned short reserved; // offset 0xA, size 0x2
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
unsigned short num; // offset 0x0, size 0x2
unsigned short subTabIndex; // offset 0x2, size 0x2
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
unsigned short id; // offset 0x4, size 0x2
unsigned short refCount; // offset 0x6, size 0x2
u16 id; // offset 0x4, size 0x2
u16 refCount; // offset 0x6, size 0x2
} MAC_SUBTAB;
typedef struct GSTACK {
@ -424,9 +424,9 @@ typedef struct SYNTHMasterFader {
float pauseStart; // offset 0x1C, size 0x4
float pauseTime; // offset 0x20, size 0x4
float pauseDeltaTime; // offset 0x24, size 0x4
unsigned long seqId; // offset 0x28, size 0x4
unsigned char seqMode; // offset 0x2C, size 0x1
unsigned char type; // offset 0x2D, size 0x1
u32 seqId; // offset 0x28, size 0x4
u8 seqMode; // offset 0x2C, size 0x1
u8 type; // offset 0x2D, size 0x1
} SYNTHMasterFader;
typedef struct CTRL_SOURCE {
@ -443,39 +443,39 @@ typedef struct CTRL_DEST {
typedef struct SND_VIRTUALSAMPLE_INFO {
// total size: 0x14
unsigned short smpID; // offset 0x0, size 0x2
unsigned short instID; // offset 0x2, size 0x2
u16 smpID; // offset 0x0, size 0x2
u16 instID; // offset 0x2, size 0x2
union vsData {
struct vsUpdate {
// total size: 0x10
unsigned long off1; // offset 0x0, size 0x4
unsigned long len1; // offset 0x4, size 0x4
unsigned long off2; // offset 0x8, size 0x4
unsigned long len2; // offset 0xC, size 0x4
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
unsigned char state; // offset 0x0, size 0x1
unsigned char hwId; // offset 0x1, size 0x1
unsigned char smpType; // offset 0x2, size 0x1
unsigned char voice; // offset 0x3, size 0x1
unsigned long last; // offset 0x4, size 0x4
unsigned long finalGoodSamples; // offset 0x8, size 0x4
unsigned long finalLast; // offset 0xC, size 0x4
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
unsigned char numBuffers; // offset 0x0, size 0x1
unsigned long bufferLength; // offset 0x4, size 0x4
u8 numBuffers; // offset 0x0, size 0x1
u32 bufferLength; // offset 0x4, size 0x4
VS_BUFFER streamBuffer[64]; // offset 0x8, size 0x900
unsigned char voices[64]; // offset 0x908, size 0x40
unsigned short nextInstID; // offset 0x948, size 0x2
unsigned long (*callback)(unsigned char,
u8 voices[64]; // offset 0x908, size 0x40
u16 nextInstID; // offset 0x948, size 0x2
u32 (*callback)(u8,
struct SND_VIRTUALSAMPLE_INFO*); // offset 0x94C, size 0x4
} VS;
@ -611,46 +611,46 @@ typedef struct SYNTH_VOICE {
typedef struct synthITDInfo {
// total size: 0x2
unsigned char music; // offset 0x0, size 0x1
unsigned char sfx; // offset 0x1, size 0x1
u8 music; // offset 0x0, size 0x1
u8 sfx; // offset 0x1, size 0x1
} synthITDInfo;
#pragma pop
typedef struct LAYER {
// total size: 0xC
unsigned short id; // offset 0x0, size 0x2
unsigned char keyLow; // offset 0x2, size 0x1
unsigned char keyHigh; // offset 0x3, size 0x1
signed char transpose; // offset 0x4, size 0x1
unsigned char volume; // offset 0x5, size 0x1
signed short prioOffset; // offset 0x6, size 0x2
unsigned char panning; // offset 0x8, size 0x1
unsigned char reserved[3]; // offset 0x9, size 0x3
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
unsigned short id; // offset 0x0, size 0x2
signed char transpose; // offset 0x2, size 0x1
unsigned char panning; // offset 0x3, size 0x1
signed short prioOffset; // offset 0x4, size 0x2
unsigned char reserved[2]; // offset 0x6, size 0x2
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
unsigned long nextOff; // offset 0x0, size 0x4
unsigned short id; // offset 0x4, size 0x2
unsigned short reserved; // offset 0x6, size 0x2
u32 nextOff; // offset 0x0, size 0x4
u16 id; // offset 0x4, size 0x2
u16 reserved; // offset 0x6, size 0x2
union {
struct {
// total size: 0x10
unsigned long num; // offset 0x0, size 0x4
u32 num; // offset 0x0, size 0x4
LAYER entry[1]; // offset 0x4, size 0xC
} layer;
KEYMAP map[128];
unsigned char tab[1];
u8 tab[1];
MSTEP cmd[1][2];
} data; // offset 0x8, size 0x400
} MEM_DATA;
@ -694,33 +694,33 @@ typedef struct SAL_PANINFO {
typedef struct _SPB {
// total size: 0x36
unsigned short dpopLHi; // offset 0x0, size 0x2
unsigned short dpopLLo; // offset 0x2, size 0x2
unsigned short dpopLDelta; // offset 0x4, size 0x2
unsigned short dpopRHi; // offset 0x6, size 0x2
unsigned short dpopRLo; // offset 0x8, size 0x2
unsigned short dpopRDelta; // offset 0xA, size 0x2
unsigned short dpopSHi; // offset 0xC, size 0x2
unsigned short dpopSLo; // offset 0xE, size 0x2
unsigned short dpopSDelta; // offset 0x10, size 0x2
unsigned short dpopALHi; // offset 0x12, size 0x2
unsigned short dpopALLo; // offset 0x14, size 0x2
unsigned short dpopALDelta; // offset 0x16, size 0x2
unsigned short dpopARHi; // offset 0x18, size 0x2
unsigned short dpopARLo; // offset 0x1A, size 0x2
unsigned short dpopARDelta; // offset 0x1C, size 0x2
unsigned short dpopASHi; // offset 0x1E, size 0x2
unsigned short dpopASLo; // offset 0x20, size 0x2
unsigned short dpopASDelta; // offset 0x22, size 0x2
unsigned short dpopBLHi; // offset 0x24, size 0x2
unsigned short dpopBLLo; // offset 0x26, size 0x2
unsigned short dpopBLDelta; // offset 0x28, size 0x2
unsigned short dpopBRHi; // offset 0x2A, size 0x2
unsigned short dpopBRLo; // offset 0x2C, size 0x2
unsigned short dpopBRDelta; // offset 0x2E, size 0x2
unsigned short dpopBSHi; // offset 0x30, size 0x2
unsigned short dpopBSLo; // offset 0x32, size 0x2
unsigned short dpopBSDelta; // offset 0x34, size 0x2
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;
typedef struct DSPhostDPop {
@ -738,10 +738,10 @@ typedef struct DSPhostDPop {
typedef struct DSPinput {
// total size: 0xC
unsigned char studio; // offset 0x0, size 0x1
unsigned short vol; // offset 0x2, size 0x2
unsigned short volA; // offset 0x4, size 0x2
unsigned short volB; // offset 0x6, size 0x2
u8 studio; // offset 0x0, size 0x1
u16 vol; // offset 0x2, size 0x2
u16 volA; // offset 0x4, size 0x2
u16 volB; // offset 0x6, size 0x2
struct SND_STUDIO_INPUT* desc; // offset 0x8, size 0x4
} DSPinput;
@ -754,9 +754,9 @@ typedef struct DSPstudioinfo {
long* auxB[3]; // offset 0x3C, size 0xC
struct DSPvoice* voiceRoot; // offset 0x48, size 0x4
struct DSPvoice* alienVoiceRoot; // offset 0x4C, size 0x4
unsigned char state; // offset 0x50, size 0x1
unsigned char isMaster; // offset 0x51, size 0x1
unsigned char numInputs; // offset 0x52, size 0x1
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
struct DSPinput in[7]; // offset 0x58, size 0x54
SND_AUX_CALLBACK auxAHandler; // offset 0xAC, size 0x4
@ -774,50 +774,50 @@ typedef s32 (*SND_COMPARE)(void*, void*);
typedef struct CHANNEL_DEFAULTS {
// total size: 0x1
unsigned char pbRange; // offset 0x0, size 0x1
u8 pbRange; // offset 0x0, size 0x1
} CHANNEL_DEFAULTS;
typedef struct FX_TAB {
// total size: 0xA
unsigned short id; // offset 0x0, size 0x2
unsigned short macro; // offset 0x2, size 0x2
unsigned char maxVoices; // offset 0x4, size 0x1
unsigned char priority; // offset 0x5, size 0x1
unsigned char volume; // offset 0x6, size 0x1
unsigned char panning; // offset 0x7, size 0x1
unsigned char key; // offset 0x8, size 0x1
unsigned char vGroup; // offset 0x9, size 0x1
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
unsigned short num; // offset 0x0, size 0x2
unsigned short reserverd; // offset 0x2, size 0x2
u16 num; // offset 0x0, size 0x2
u16 reserverd; // offset 0x2, size 0x2
struct FX_TAB fx[1]; // offset 0x4, size 0xA
} FX_DATA;
typedef struct FX_GROUP {
// total size: 0x8
unsigned short gid; // offset 0x0, size 0x2
unsigned short fxNum; // offset 0x2, size 0x2
u16 gid; // offset 0x0, size 0x2
u16 fxNum; // offset 0x2, size 0x2
struct FX_TAB* fxTab; // offset 0x4, size 0x4
} FX_GROUP;
typedef struct PAGE {
// total size: 0x6
unsigned short macro; // offset 0x0, size 0x2
unsigned char prio; // offset 0x2, size 0x1
unsigned char maxVoices; // offset 0x3, size 0x1
unsigned char index; // offset 0x4, size 0x1
unsigned char reserved; // offset 0x5, size 0x1
u16 macro; // offset 0x0, size 0x2
u8 prio; // offset 0x2, size 0x1
u8 maxVoices; // offset 0x3, size 0x1
u8 index; // offset 0x4, size 0x1
u8 reserved; // offset 0x5, size 0x1
} PAGE;
typedef struct MIDI_CHANNEL_SETUP {
// total size: 0x5
unsigned char program; // offset 0x0, size 0x1
unsigned char volume; // offset 0x1, size 0x1
unsigned char panning; // offset 0x2, size 0x1
unsigned char reverb; // offset 0x3, size 0x1
unsigned char chorus; // offset 0x4, size 0x1
u8 program; // offset 0x0, size 0x1
u8 volume; // offset 0x1, size 0x1
u8 panning; // offset 0x2, size 0x1
u8 reverb; // offset 0x3, size 0x1
u8 chorus; // offset 0x4, size 0x1
} MIDI_CHANNEL_SETUP;
typedef struct MIDISETUP {
@ -834,17 +834,17 @@ typedef struct ADSR_INFO {
// total size: 0x14
long atime; // offset 0x0, size 0x4
long dtime; // offset 0x4, size 0x4
unsigned short slevel; // offset 0x8, size 0x2
unsigned short rtime; // offset 0xA, size 0x2
u16 slevel; // offset 0x8, size 0x2
u16 rtime; // offset 0xA, size 0x2
long ascale; // offset 0xC, size 0x4
long dscale; // offset 0x10, size 0x4
} dls;
struct {
// total size: 0x8
unsigned short atime; // offset 0x0, size 0x2
unsigned short dtime; // offset 0x2, size 0x2
unsigned short slevel; // offset 0x4, size 0x2
unsigned short rtime; // offset 0x6, size 0x2
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;
@ -870,22 +870,25 @@ FX_TAB* dataGetFX(u16 fid);
s32 hwInit(u32* frq, u16 numVoices, u16 numStudios, u32 flags); /* extern */
void hwInitSamplePlayback(u32 v, u16 smpID, void* newsmp, u32 set_defadsr, u32 prio,
u32 callbackUserValue, u32 setSRC, u8 itdMode);
void hwSetVolume(u32 v, u8 table, float vol, u32 pan, u32 span, float auxa, float auxb);
void hwSetPitch(u32 v, u16 speed);
void hwEnableIrq();
void hwDisableIrq();
void* hwTransAddr(void* samples);
void seqInit(); /* extern */
unsigned long seqStartPlay(PAGE* norm, PAGE* drum, MIDISETUP* midiSetup, u32* song,
SND_PLAYPARA* para, u8 studio, u16 sgid);
unsigned long seqGetPrivateId(unsigned long seqId);
u32 seqStartPlay(PAGE* norm, PAGE* drum, MIDISETUP* midiSetup, u32* song, SND_PLAYPARA* para,
u8 studio, u16 sgid);
u32 seqGetPrivateId(u32 seqId);
void streamInit(); /* extern */
void vsInit(); /* extern */
void hwExit();
void dataExit();
void s3dInit(s32); /* extern */
void s3dKillEmitterByFXID(FX_TAB* fxTab, unsigned long num);
void s3dKillEmitterByFXID(FX_TAB* fxTab, u32 num);
void s3dExit();
void synthInit(u32, u8); /* extern */
void synthSetBpm(u32 pbm, u8 set, u8 section);
void synthFXCloneMidiSetup(SYNTH_VOICE* dest, SYNTH_VOICE* src);
void synthSetMusicVolumeType(u8 vGroup, u8 type);
@ -895,7 +898,7 @@ extern u8 voiceMusicRunning;
extern u8 voiceFxRunning;
extern u8 voiceListInsert;
extern u8 voiceListRoot;
void voiceSetPriority(struct SYNTH_VOICE* svoice, unsigned char prio);
void voiceSetPriority(struct SYNTH_VOICE* svoice, u8 prio);
u32 voiceIsLastStarted(struct SYNTH_VOICE* svoice);
s32 voiceKillSound(u32 voiceid);
@ -909,13 +912,19 @@ 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);
void hwActivateStudio(unsigned char studio, unsigned long isMaster, SND_STUDIO_TYPE type);
u32 sndStreamAllocLength(u32 num, u32 flags);
void sndStreamFree(u32 stid);
u32 sndStreamActivate(u32 stid);
void sndStreamDeactivate(u32 stid);
void hwActivateStudio(u8 studio, u32 isMaster, SND_STUDIO_TYPE type);
void hwDeactivateStudio(u8);
void hwSetPriority(unsigned long v, unsigned long prio);
void hwSetPriority(u32 v, u32 prio);
u32 hwIsActive(u32);
u32 hwGlobalActivity();
void hwSetAUXProcessingCallbacks(unsigned char studio, SND_AUX_CALLBACK auxA, void* userA,
void hwSetAUXProcessingCallbacks(u8 studio, SND_AUX_CALLBACK auxA, void* userA,
SND_AUX_CALLBACK auxB, void* userB);
u8 hwInitStream(u32 len);
s16 varGet(SYNTH_VOICE* svoice, u32 ctrl, u8 index);
u32 sndGetPitch(u8 key, u32 sInfo);
@ -944,7 +953,7 @@ 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(unsigned char studio);
void salDeactivateStudio(u8 studio);
void salActivateVoice(DSPvoice* dsp_vptr, u8 studio);
void salCalcVolume(u8 voltab_index, SAL_VOLINFO* vi, float vol, u32 pan, u32 span, float auxa,
float auxb, u32 itd, u32 dpl2);
@ -959,38 +968,75 @@ extern u8 salNumVoices;
/* Stream */
typedef s32 (*SND_STREAM_UPDATE_CALLBACK)(void* buffer1, u32 len1, void* buffer2, u32 len2,
void* user);
typedef struct SND_STREAM_INFO {
u32 x0_;
u32 x4_;
u32 x8_;
u8 xc_;
char data2[0x10 - 0xd];
SND_STREAM_UPDATE_CALLBACK updateCb;
char data3[0x4C - 0x14];
SND_VOICEID voiceId;
void* user;
char data4[0x64 - 0x54];
} SND_STREAM_INFO;
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;
#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;
void streamOutputModeChanged();
u8 inpTranslateExCtrl(unsigned char ctrl);
u8 inpTranslateExCtrl(u8 ctrl);
void inpSetGlobalMIDIDirtyFlag(u8 chan, u8 midiSet, s32 flag);
void inpAddCtrl(struct CTRL_DEST* dest, unsigned char ctrl, long scale, unsigned char comb,
unsigned long isVar);
void inpSetExCtrl(SYNTH_VOICE* svoice, unsigned char ctrl, signed short v);
CHANNEL_DEFAULTS* inpGetChannelDefaults(unsigned char midi, unsigned char midiSet);
void inpAddCtrl(struct CTRL_DEST* dest, u8 ctrl, long scale, u8 comb, u32 isVar);
void inpSetExCtrl(SYNTH_VOICE* svoice, u8 ctrl, s16 v);
CHANNEL_DEFAULTS* inpGetChannelDefaults(u8 midi, u8 midiSet);
extern CTRL_DEST inpAuxA[8][4];
extern CTRL_DEST inpAuxB[8][4];
void inpSetMidiLastNote(u8 midi, u8 midiSet, u8 key);
u8 inpGetMidiLastNote(u8 midi, u8 midiSet);
unsigned short inpGetExCtrl(SYNTH_VOICE* svoice, unsigned char ctrl);
unsigned short inpGetMidiCtrl(unsigned char ctrl, unsigned char channel, unsigned char set);
void inpSetMidiLastNote(unsigned char midi, unsigned char midiSet, unsigned char key);
u16 inpGetExCtrl(SYNTH_VOICE* svoice, u8 ctrl);
u16 inpGetMidiCtrl(u8 ctrl, u8 channel, u8 set);
void inpSetMidiLastNote(u8 midi, u8 midiSet, u8 key);
u16 inpGetModulation(SYNTH_VOICE* svoice);
/* TODO: Figure out what `unk` is */
void hwSetSRCType(u32 v, u8 salSRCType);
void hwSetITDMode(u32 v, u8 mode);
void hwSetPolyPhaseFilter(unsigned long v, unsigned char salCoefSel);
void hwSetPolyPhaseFilter(u32 v, u8 salCoefSel);
bool hwAddInput(u8 studio, SND_STUDIO_INPUT* in_desc);
bool hwRemoveInput(u8 studio, SND_STUDIO_INPUT* in_desc);
void hwChangeStudio(u32 v, u8 studio);
@ -1005,19 +1051,15 @@ extern u8 dspScale2IndexTab[1024];
typedef void* (*ARAMUploadCallback)(u32, u32);
u32 aramGetStreamBufferAddress(unsigned char id, unsigned long* len);
void aramUploadData(void* mram, unsigned long aram, unsigned long len, unsigned long highPrio,
void (*callback)(unsigned long), unsigned long user);
u32 aramGetStreamBufferAddress(u8 id, u32* len);
void aramUploadData(void* mram, u32 aram, u32 len, u32 highPrio, void (*callback)(u32), u32 user);
void aramFreeStreamBuffer(u8 id);
void* aramStoreData(void* src, unsigned long len);
void aramRemoveData(void* aram, unsigned long len);
unsigned long macStart(unsigned short macid, unsigned char priority, unsigned char maxVoices,
unsigned short allocId, unsigned char key, unsigned char vol,
unsigned char panning, unsigned char midi, unsigned char midiSet,
unsigned char section, unsigned short step, unsigned short trackid,
unsigned char new_vid, unsigned char vGroup, unsigned char studio,
unsigned long itd);
void* aramStoreData(void* src, u32 len);
void aramRemoveData(void* aram, u32 len);
u8 aramAllocateStreamBuffer(u32 len);
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 macMakeInactive(SYNTH_VOICE* svoice, MAC_STATE);
void sndProfUpdateMisc(SND_PROFILE_INFO* info);

View File

@ -7,6 +7,160 @@
extern "C" {
#endif
typedef struct ARR {
// total size: 0x58
unsigned long tTab; // offset 0x0, size 0x4
unsigned long pTab; // offset 0x4, size 0x4
unsigned long tmTab; // offset 0x8, size 0x4
unsigned long mTrack; // offset 0xC, size 0x4
unsigned long info; // offset 0x10, size 0x4
unsigned long loopPoint[16]; // offset 0x14, size 0x40
unsigned long tsTab; // offset 0x54, size 0x4
} ARR;
typedef struct TENTRY {
// total size: 0xC
u32 time; // offset 0x0, size 0x4
u8 prgChange; // offset 0x4, size 0x1
u8 velocity; // offset 0x5, size 0x1
u8 res[2]; // offset 0x6, size 0x2
u16 pattern; // offset 0x8, size 0x2
s8 transpose; // offset 0xA, size 0x1
s8 velocityAdd; // offset 0xB, size 0x1
} TENTRY;
typedef struct TRACK {
// total size: 0x8
struct TENTRY* base; // offset 0x0, size 0x4
struct TENTRY* addr; // offset 0x4, size 0x4
} TRACK;
typedef struct NOTE {
// total size: 0x14
struct NOTE* next; // offset 0x0, size 0x4
struct NOTE* prev; // offset 0x4, size 0x4
u32 id; // offset 0x8, size 0x4
s32 endTime; // offset 0xC, size 0x4
u8 section; // offset 0x10, size 0x1
u8 timeIndex; // offset 0x11, size 0x1
u8 reserved[2]; // offset 0x12, size 0x2
} NOTE;
typedef struct NOTE_DATA {
// total size: 0x6
u16 time; // offset 0x0, size 0x2
u8 key; // offset 0x2, size 0x1
u8 velocity; // offset 0x3, size 0x1
u16 length; // offset 0x4, size 0x2
} NOTE_DATA;
typedef struct PRG_STATE {
// total size: 0x4
u16 macId; // offset 0x0, size 0x2
u8 priority; // offset 0x2, size 0x1
u8 maxVoices; // offset 0x3, size 0x1
} PRG_STATE;
typedef struct SEQ_STREAM {
// total size: 0xC
u8* nextAddr; // offset 0x0, size 0x4
u16 value; // offset 0x4, size 0x2
s16 nextDelta; // offset 0x6, size 0x2
u32 nextTime; // offset 0x8, size 0x4
} SEQ_STREAM;
typedef struct CPAT {
// total size: 0x2C
u32 lTime; // offset 0x0, size 0x4
u32 baseTime; // offset 0x4, size 0x4
NOTE_DATA* addr; // offset 0x8, size 0x4
TENTRY* patternInfo; // offset 0xC, size 0x4
SEQ_STREAM pitchBend; // offset 0x10, size 0xC
SEQ_STREAM modulation; // offset 0x1C, size 0xC
u8 midi; // offset 0x28, size 0x1
} CPAT;
typedef struct SEQ_EVENT {
// total size: 0x18
struct SEQ_EVENT* next; // offset 0x0, size 0x4
struct SEQ_EVENT* prev; // offset 0x4, size 0x4
u32 time; // offset 0x8, size 0x4
union evInfo {
TENTRY* trackAddr;
struct {
// total size: 0x8
NOTE_DATA* addr; // offset 0x0, size 0x4
CPAT* base; // offset 0x4, size 0x4
} pattern;
} info; // offset 0xC, size 0x8
u8 type; // offset 0x14, size 0x1
u8 trackId; // offset 0x15, size 0x1
} SEQ_EVENT;
typedef struct MTRACK_DATA {
// total size: 0x8
u32 time; // offset 0x0, size 0x4
u32 bpm; // offset 0x4, size 0x4
} MTRACK_DATA;
typedef struct MTRACK {
// total size: 0x8
MTRACK_DATA* base; // offset 0x0, size 0x4
MTRACK_DATA* addr; // offset 0x4, size 0x4
} MTRACK;
typedef struct TICKS {
// total size: 0x8
u32 low; // offset 0x0, size 0x4
long high; // offset 0x4, size 0x4
} TICKS;
typedef struct SEQ_SECTION {
// total size: 0x38
struct MTRACK mTrack; // offset 0x0, size 0x8
u32 bpm; // offset 0x8, size 0x4
TICKS tickDelta[2]; // offset 0xC, size 0x10
SEQ_EVENT* globalEventRoot; // offset 0x1C, size 0x4
TICKS time[2]; // offset 0x20, size 0x10
u8 timeIndex; // offset 0x30, size 0x1
u16 speed; // offset 0x32, size 0x2
u16 loopCnt; // offset 0x34, size 0x2
u8 loopDisable; // offset 0x36, size 0x1
} SEQ_SECTION;
typedef struct SEQ_INSTANCE {
// total size: 0x1868
struct SEQ_INSTANCE* next; // offset 0x0, size 0x4
struct SEQ_INSTANCE* prev; // offset 0x4, size 0x4
u8 state; // offset 0x8, size 0x1
u8 index; // offset 0x9, size 0x1
u16 groupID; // offset 0xA, size 0x2
u32 publicId; // offset 0xC, size 0x4
PAGE* normtab; // offset 0x10, size 0x4
u8 normTrans[128]; // offset 0x14, size 0x80
PAGE* drumtab; // offset 0x94, size 0x4
u8 drumTrans[128]; // offset 0x98, size 0x80
ARR* arrbase; // offset 0x118, size 0x4
u32 trackMute[2]; // offset 0x11C, size 0x8
TRACK track[64]; // offset 0x124, size 0x200
u8 trackVolGroup[64]; // offset 0x324, size 0x40
CPAT pattern[64]; // offset 0x364, size 0xB00
NOTE* noteUsed[2]; // offset 0xE64, size 0x8
NOTE* noteKeyOff; // offset 0xE6C, size 0x4
PRG_STATE prgState[16]; // offset 0xE70, size 0x40
u8 defVGroup; // offset 0xEB0, size 0x1
SND_CROSSFADE syncCrossInfo; // offset 0xEB4, size 0x28
u32* syncSeqIdPtr; // offset 0xEDC, size 0x4
u8 syncActive; // offset 0xEE0, size 0x1
u8 defStudio; // offset 0xEE1, size 0x1
u8 keyOffCheck; // offset 0xEE2, size 0x1
SEQ_EVENT event[64]; // offset 0xEE4, size 0x600
u8* trackSectionTab; // offset 0x14E4, size 0x4
SEQ_SECTION section[16]; // offset 0x14E8, size 0x380
} SEQ_INSTANCE;
extern u8 synthTrackVolume[64];
extern SEQ_INSTANCE seqInstance[8];
extern u16 seqMIDIPriority[8][16];
void sndSeqStop(s32 unk);
@ -14,6 +168,7 @@ void sndSeqSpeed(s32 unk1, s32 unk2);
void sndSeqContinue(s32 unk);
void sndSeqMute(s32 unk1, s32 unk2, s32 unk3);
void sndSeqVolume(s32 unk1, s32 unk2, s32 unk3, s32 unk4);
void seqStop(unsigned long seqId);
u16 seqGetMIDIPriority(s32 unk1, s32 unk2);
#ifdef __cplusplus

View File

@ -23,7 +23,8 @@ bool synthFXSetCtrl(SND_VOICEID vid, u8 ctrl, u8 value);
bool synthFXSetCtrl14(SND_VOICEID vid, u8 ctrl, u16 value);
bool synthSendKeyOff(SND_VOICEID vid);
SND_VOICEID synthFXStart(SND_FXID fid, u8 vol, u8 pan, u8 studio, u8);
void synthVolume(u8 volume, u16 time, u8 volgroup2, s32, s32);
void synthVolume(unsigned char volume, unsigned short time, unsigned char vGroup,
unsigned char seqMode, unsigned long seqId);
/* TODO: Move this where it belongs */
void hwSetAUXProcessingCallbacks(u8 studio, SND_AUX_CALLBACK auxA, void* userA,

View File

@ -88,6 +88,7 @@ double ldexp(double x, int exp);
double copysign(double x, double y);
double floor(double x);
float floorf(float x) { return floor(x); }
double fabs(double x);
double pow(double x, double y);

View File

@ -1,17 +1,54 @@
/*
*/
#include "dolphin/GBAPriv.h"
static GBASecParams SecParams[4];
static GBASecParam SecParams[4];
GBAControl __GBA[4];
BOOL __GBAReset = FALSE;
static BOOL OnReset(BOOL);
static OSResetFunctionInfo ResetFunctionInfo = {
OnReset,
127
};
static OSResetFunctionInfo ResetFunctionInfo = {OnReset, 127};
void ShortCommandProc(s32 chan) {
static void ShortCommandProc(s32 chan) {
GBAControl* gba;
gba = &__GBA[chan];
@ -27,6 +64,19 @@ void ShortCommandProc(s32 chan) {
gba->status[0] = gba->input[2] & GBA_JSTAT_MASK;
}
/*
*/
void GBAInit() {
GBAControl* gba;
s32 chan;
@ -37,16 +87,37 @@ void GBAInit() {
OSInitThreadQueue(&gba->threadQueue);
gba->param = &SecParams[chan];
// ASSERTMSG((u32) gba->param % 32 == 0)
ASSERT((u32) gba->param % 32 == 0);
}
OSInitAlarm();
DSPInit();
__GBAReset = FALSE;
DSPInit();
__GBAReset = FALSE;
OSRegisterResetFunction(&ResetFunctionInfo);
}
/*
*/
s32 GBAGetStatusAsync(s32 chan, u8* status, GBACallback callback) {
GBAControl* gba;
gba = &__GBA[chan];
@ -59,43 +130,89 @@ s32 GBAGetStatusAsync(s32 chan, u8* status, GBACallback callback) {
gba->callback = callback;
return __GBATransfer(chan, 1, 3, ShortCommandProc);
}
/*
*/
s32 GBAGetStatus(s32 chan, u8* status) {
GBAControl* gba = &__GBA[chan];
//
s32 ret = GBAGetStatusAsync(chan, status, __GBASyncCallback);
return ret != GBA_READY ? ret : __GBASync(chan);
if (ret != GBA_READY) {
return ret;
}
return __GBASync(chan);
}
/*
*/
s32 GBAResetAsync(s32 chan, u8* status, GBACallback callback) {
GBAControl* gba;
GBAControl* gba = &__GBA[chan];
s32 ret;
gba = &__GBA[chan];
if (gba->callback != NULL) {
ret = GBA_BUSY;
} else {
return GBA_BUSY;
}
gba->output[0] = 0xFF;
gba->status = status;
gba->callback = callback;
ret = __GBATransfer(chan, 1, 3, ShortCommandProc);
}
return ret;
return __GBATransfer(chan, 1, 3, ShortCommandProc);
}
/*
*/
s32 GBAReset(s32 chan, u8* status) {
GBAControl* gba = &__GBA[chan];
s32 ret;
ret = GBAResetAsync(chan, status, __GBASyncCallback);
if (ret != GBA_READY) {
return ret;
}
return __GBASync(chan);
}
/*
*/
BOOL OnReset(BOOL) {
__GBAReset = TRUE;
return TRUE;

View File

@ -1,14 +1,71 @@
/*
*/
#include "dolphin/GBAPriv.h"
/*
*/
s32 GBAGetProcessStatus(s32 chan, u8* percentp) {
BOOL enabled;
s32 ret; // r29
GBAControl * gba; // r25
GBABootInfo * bootInfo; // r31
GBAControl* gba = &__GBA[chan]; // r25
GBABootInfo* bootInfo; // r31
u8 percent; // r30
OSTime t; // r27
gba = &__GBA[chan];
bootInfo = &gba->bootInfo;
enabled = OSDisableInterrupts();
@ -17,9 +74,12 @@ s32 GBAGetProcessStatus(s32 chan, u8* percentp) {
percent = (bootInfo->curOffset * 100) / bootInfo->realLength;
if (bootInfo->begin != 0) {
t = OSGetTime();
if (OSTicksToMilliseconds(t - bootInfo->begin) < (5500)) {
percent = ((t - bootInfo->begin) * percent) / OSMillisecondsToTicks((OSTime)5500);
}
if (t - bootInfo->begin < OSMillisecondsToTicks(5500)) {
percentp = 0;
if (percent >= 100) {
percent = 100;
}
}

View File

@ -17,22 +17,24 @@ static void F37(s32 chan, s32 ret);
static void F39(s32 chan, s32 ret);
static u32 F72(u32 crc, u32 src, vu8* keyp) {
int i;
int poly;
int i; // r31
int poly =
(keyp[0x13] << 8) + ((keyp[0x15] + (keyp[0x18] - (keyp[0x18] << 4))) - keyp[0x10]); // r30
for (i = keyp[1]; i > keyp[11]; --i) {
if ((src ^ crc) & 1 != 0) {
crc = (crc >> 1) ^ ((keyp[19] * 256 + keyp[21] + keyp[24] + keyp[24] * -16) - keyp[16]);
if ((src ^ crc) & 1) {
crc >>= 1;
crc ^= poly;
} else {
crc >>= 1;
}
src >>= 1;
}
}
u32 F95(u32 src, vu8* keyp) {
return src * ((keyp[3] << keyp[0x16]) | keyp[1] | (keyp[4] << keyp[0x11]) |
(keyp[4] << keyp[0x18])) -
return src * ((keyp[4] << keyp[0x11]) | keyp[1] | (keyp[4] << keyp[0x18]) |
(keyp[3] << keyp[0x16])) -
(keyp[7] - keyp[6]);
}
@ -52,20 +54,20 @@ static void F104(s32 chan, s32 ret) {
s32 GBAJoyBootAsync(s32 chan, s32 paletteColor, s32 paletteSpeed, u8* programp, s32 length,
u8* status, GBACallback callback) {
int ret;
GBABootInfo* bootInfo;
GBABootInfo* bootInfo = &__GBA[chan].bootInfo;
u8 percent;
bootInfo = &__GBA[chan].bootInfo;
if (chan & ~3) {
ret = GBA_JOYBOOT_ERR_INVALID;
return GBA_JOYBOOT_ERR_INVALID;
} else if (length == 0 || GBA_JOYBOOT_PROGRAM_SIZE_MAX < length) {
ret = GBA_JOYBOOT_ERR_INVALID;
return GBA_JOYBOOT_ERR_INVALID;
} else if (paletteSpeed < -4 || paletteSpeed > 4) {
ret = GBA_JOYBOOT_ERR_INVALID;
return GBA_JOYBOOT_ERR_INVALID;
} else if (paletteColor < 0 || paletteColor > 6) {
ret = GBA_JOYBOOT_ERR_INVALID;
return GBA_JOYBOOT_ERR_INVALID;
} else if (programp[0xac] * programp[0xad] * programp[0xae] * programp[0xaf] == 0) {
ret = GBA_JOYBOOT_ERR_INVALID;
} else {
return GBA_JOYBOOT_ERR_INVALID;
}
ret = GBAGetProcessStatus(chan, &percent);
if (ret != 0) {
return ret;
@ -82,7 +84,6 @@ s32 GBAJoyBootAsync(s32 chan, s32 paletteColor, s32 paletteSpeed, u8* programp,
if (ret != GBA_READY) {
bootInfo->callback = NULL;
}
}
return ret;
}
@ -91,7 +92,7 @@ static void F23(s32 chan, s32 ret) {
GBABootInfo* bootInfo;
gba = &__GBA[chan];
bootInfo = &gba->bootInfo;
bootInfo = &__GBA[chan].bootInfo;
if (ret != GBA_READY || (ret = GBAResetAsync(chan, bootInfo->status, F25)) != GBA_READY) {
F104(chan, ret);
@ -102,7 +103,7 @@ static void F23(s32 chan, s32 ret) {
static void F25(s32 chan, s32 ret) {
GBAControl* gba = &__GBA[chan];
GBABootInfo* bootInfo = &gba->bootInfo;
GBABootInfo* bootInfo = &__GBA[chan].bootInfo;
if (ret == GBA_READY && *bootInfo->status != D54[37]) {
ret = GBA_JOYBOOT_UNKNOWN_STATE;
@ -117,7 +118,7 @@ static void F25(s32 chan, s32 ret) {
static void F27(s32 chan, s32 ret) {
GBAControl* gba = &__GBA[chan];
GBABootInfo* bootInfo = &gba->bootInfo;
GBABootInfo* bootInfo = &__GBA[chan].bootInfo;
if (ret == GBA_READY && *bootInfo->status != D54[0]) {
ret = GBA_JOYBOOT_UNKNOWN_STATE;
@ -132,7 +133,7 @@ static void F27(s32 chan, s32 ret) {
static void F29(s32 chan, s32 ret) {
GBAControl* gba = &__GBA[chan];
GBABootInfo* bootInfo = &gba->bootInfo;
GBABootInfo* bootInfo = &__GBA[chan].bootInfo;
if (ret == GBA_READY) {
__GBAX02(chan, bootInfo->readbuf);
@ -144,7 +145,7 @@ static void F29(s32 chan, s32 ret) {
}
void __GBAX01(s32 chan, s32 ret) {
GBAControl* gba = &__GBA[chan];
GBABootInfo* bootInfo = &gba->bootInfo;
GBABootInfo* bootInfo = &__GBA[chan].bootInfo;
int val200;
if (ret == GBA_READY) {
@ -184,11 +185,9 @@ void __GBAX01(s32 chan, s32 ret) {
}
static void F31(s32 chan, s32 ret) {
GBAControl* gba;
GBABootInfo* bootInfo;
GBAControl* gba = &__GBA[chan];
GBABootInfo* bootInfo = &__GBA[chan].bootInfo;
u32 writeWord;
gba = &__GBA[chan];
bootInfo = &gba->bootInfo;
if (ret == GBA_READY) {
if (bootInfo->firstXfer != FALSE) {
@ -232,10 +231,11 @@ static void F31(s32 chan, s32 ret) {
writeWord = bootInfo->crc | (bootInfo->curOffset << 16);
}
if (D54[43] < bootInfo->curOffset) {
if (bootInfo->curOffset > D54[43]) {
bootInfo->keyA = F95(bootInfo->keyA, &D54[20]);
writeWord ^= bootInfo->keyA ^ -(bootInfo->curOffset + D54[11] * 0x100000) ^
((D54[18] << 8) | (D54[19] << 16) | (D54[11] << 24) | D54[11]);
writeWord ^= bootInfo->keyA;
writeWord ^= -(bootInfo->curOffset + D54[11] * 0x100000);
writeWord ^= (D54[11] | (D54[11] << 24)) | (D54[19] << 16) | (D54[18] << 8);
}
bootInfo->writebuf[3] = (writeWord >> D54[0]);
@ -248,7 +248,13 @@ static void F31(s32 chan, s32 ret) {
}
if (bootInfo->i < D54[33]) {
bootInfo->dummyWord[bootInfo->i] = writeWord;
bootInfo->dummyWord[3 - (1 - bootInfo->i)] = writeWord;
bootInfo->dummyWord[5 - bootInfo->i] =
bootInfo->dummyWord[(2 - (1 - bootInfo->i))] * bootInfo->dummyWord[4 - bootInfo->i];
bootInfo->dummyWord[5 - (1 - bootInfo->i)] =
bootInfo->dummyWord[((1 - bootInfo->i))] * bootInfo->dummyWord[1 - (1 - bootInfo->i)];
bootInfo->dummyWord[7 - bootInfo->i] =
bootInfo->dummyWord[(-(1 - bootInfo->i))] * bootInfo->dummyWord[4 - bootInfo->i];
}
ret = GBAWriteAsync(chan, bootInfo->writebuf, bootInfo->status, F31);
@ -266,7 +272,7 @@ exit:
}
static void F33(s32 chan, s32 ret) {
GBAControl* gba = &__GBA[chan];
GBABootInfo* bootInfo = &gba->bootInfo;
GBABootInfo* bootInfo = &__GBA[chan].bootInfo;
if (ret == GBA_READY) {
for (bootInfo->i = 33; bootInfo->i < 36; ++bootInfo->i) {
@ -297,7 +303,7 @@ static void F33(s32 chan, s32 ret) {
}
static void F35(s32 chan, s32 ret) {
GBAControl* gba = &__GBA[chan];
GBABootInfo* bootInfo = &gba->bootInfo;
GBABootInfo* bootInfo = &__GBA[chan].bootInfo;
if (ret == 0) {
if (OSSecondsToTicks(10) <= OSGetTick() - bootInfo->start) {
@ -322,7 +328,7 @@ static void F35(s32 chan, s32 ret) {
static void F37(s32 chan, s32 ret) {
GBAControl* gba = &__GBA[chan];
GBABootInfo* bootInfo = &gba->bootInfo;
GBABootInfo* bootInfo = &__GBA[chan].bootInfo;
if (ret == GBA_READY) {
if ((((bootInfo->readbuf[3] ^ (bootInfo->initialCode >> 24)) |
@ -344,7 +350,7 @@ static void F37(s32 chan, s32 ret) {
static void F39(s32 chan, s32 ret) {
GBAControl* gba = &__GBA[chan];
GBABootInfo* bootInfo = &gba->bootInfo;
GBABootInfo* bootInfo = &__GBA[chan].bootInfo;
if (ret == GBA_READY) {
*bootInfo->status = 0;
@ -354,13 +360,12 @@ static void F39(s32 chan, s32 ret) {
gba->ret = ret;
}
s32 GBAJoyBoot(s32 chan, s32 paletteColor, s32 paletteSpeed, unsigned char* programp, s32 length,
unsigned char* status) {
s32 GBAJoyBoot(s32 chan, s32 paletteColor, s32 paletteSpeed, u8* programp, s32 length, u8* status) {
s32 ret = GBAJoyBootAsync(chan, paletteColor, paletteSpeed, programp, length, status,
__GBASyncCallback);
if (ret == GBA_READY) {
ret = __GBASync(chan);
if (ret != GBA_READY) {
return ret;
}
return ret;
return __GBASync(chan);
}

116
src/Dolphin/GBA/GBAKey.c Normal file
View File

@ -0,0 +1,116 @@
#include "dolphin/GBAPriv.h"
static volatile u8 D35[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 33, 2, 255, 0, 33, 19, 6, 18, 3, 18, 4,
19, 5, 0, 146, 0, 255, 0, 136, 255, 255, 0, 137, 255, 255, 0, 138, 255, 255, 0,
139, 255, 255, 143, 0, 139, 0, 140, 0, 2, 191, 128, 126, 22, 252, 220, 209, 22, 253,
0, 0, 22, 251, 0, 1, 2, 191, 128, 120, 36, 255, 2, 128, 171, 186, 2, 148, 0,
41, 142, 0, 2, 191, 128, 120, 32, 255, 2, 64, 15, 255, 31, 94, 0, 155, 0, 0,
0, 153, 0, 32, 0, 135, 0, 0, 0, 128, 0, 65, 2, 159, 128, 188, 2, 191, 0,
140, 2, 191, 128, 126, 22, 252, 220, 209, 22, 253, 0, 3, 22, 251, 0, 1, 143, 0,
2, 191, 128, 120, 2, 128, 205, 209, 2, 148, 0, 76, 38, 255, 2, 128, 0, 1, 2,
149, 0, 94, 2, 128, 0, 2, 2, 149, 128, 0, 2, 159, 0, 76, 0, 33, 142, 0,
2, 191, 128, 120, 36, 255, 2, 191, 128, 120, 36, 255, 2, 191, 128, 120, 36, 255, 2,
191, 128, 120, 0, 197, 255, 255, 2, 64, 15, 255, 28, 158, 2, 191, 128, 120, 0, 199,
255, 255, 2, 191, 128, 120, 0, 198, 255, 255, 2, 191, 128, 120, 0, 192, 255, 255, 2,
191, 128, 120, 32, 255, 2, 64, 15, 255, 31, 94, 2, 191, 128, 120, 33, 255, 2, 191,
128, 120, 35, 255, 18, 5, 18, 6, 2, 159, 128, 181, 0, 33, 129, 0, 0, 129, 0,
16, 16, 32, 27, 62, 0, 223, 20, 86, 3, 64, 255, 208, 132, 23, 0, 128, 0, 0,
0, 134, 0, 0, 0, 130, 0, 31, 0, 222, 21, 246, 20, 8, 0, 223, 23, 102, 3,
64, 0, 255, 31, 95, 2, 191, 136, 229, 31, 28, 129, 30, 25, 30, 20, 120, 31, 252,
31, 94, 2, 191, 136, 9, 2, 191, 135, 35, 0, 6, 129, 6, 0, 222, 22, 108, 20,
4, 2, 64, 255, 0, 0, 223, 18, 49, 21, 120, 3, 64, 0, 255, 31, 95, 2, 191,
136, 229, 31, 28, 129, 30, 25, 30, 20, 120, 31, 252, 31, 94, 2, 191, 136, 9, 2,
191, 135, 35, 129, 0, 137, 0, 0, 209, 0, 5, 153, 0, 130, 0, 2, 149, 0, 229,
2, 145, 0, 243, 0, 130, 0, 16, 0, 134, 0, 1, 0, 208, 23, 27, 145, 0, 125,
0, 77, 0, 21, 1, 31, 95, 0, 223, 0, 3, 21, 4, 2, 191, 136, 9, 2, 159,
1, 2, 0, 130, 0, 17, 0, 223, 0, 3, 21, 1, 31, 95, 0, 222, 16, 67, 2,
64, 255, 240, 2, 191, 136, 229, 2, 159, 1, 2, 0, 130, 0, 16, 0, 134, 0, 1,
0, 208, 18, 133, 145, 0, 77, 0, 21, 1, 0, 222, 0, 3, 20, 4, 31, 94, 2,
191, 136, 9, 0, 131, 0, 19, 27, 126, 137, 35, 0, 131, 0, 19, 0, 223, 0, 7,
0, 222, 17, 184, 2, 64, 255, 240, 31, 94, 2, 191, 129, 244, 241, 0, 2, 191, 132,
88, 143, 0, 0, 130, 0, 21, 0, 222, 0, 6, 0, 218, 22, 91, 2, 191, 136, 229,
20, 253, 20, 3, 27, 94, 27, 92, 0, 130, 0, 22, 0, 222, 23, 35, 20, 244, 0,
218, 22, 107, 2, 191, 136, 229, 177, 0, 2, 144, 1, 46, 129, 0, 20, 253, 142, 0,
0, 223, 20, 145, 3, 64, 208, 240, 28, 191, 0, 223, 20, 104, 0, 209, 17, 252, 21,
124, 28, 223, 0, 209, 17, 184, 153, 0, 20, 24, 20, 120, 31, 94, 31, 254, 31, 101,
54, 0, 20, 2, 31, 102, 55, 0, 21, 1, 76, 0, 21, 24, 153, 0, 53, 0, 76,
0, 0, 223, 0, 18, 63, 0, 0, 255, 0, 18, 20, 112, 0, 223, 0, 17, 63, 0,
0, 255, 0, 17, 31, 165, 21, 1, 31, 230, 241, 0, 21, 248, 245, 0, 31, 95, 31,
125, 129, 0, 0, 222, 0, 17, 52, 0, 137, 0, 0, 223, 0, 18, 53, 0, 76, 0,
0, 223, 0, 18, 21, 120, 76, 0, 137, 0, 31, 254, 21, 8, 59, 0, 0, 222, 0,
17, 62, 0, 0, 223, 0, 18, 59, 0, 28, 191, 0, 218, 21, 241, 53, 0, 2, 149,
1, 146, 0, 223, 16, 226, 21, 8, 31, 95, 0, 223, 16, 59, 121, 0, 57, 0, 48,
128, 0, 254, 0, 34, 0, 220, 18, 41, 0, 221, 17, 248, 92, 0, 240, 0, 31, 229,
48, 128, 2, 159, 1, 165, 0, 223, 16, 202, 21, 8, 31, 95, 0, 223, 16, 67, 117,
0, 57, 0, 48, 128, 0, 254, 0, 34, 0, 220, 18, 89, 0, 221, 22, 254, 76, 0,
240, 0, 31, 229, 48, 128, 0, 254, 0, 35, 0, 218, 0, 8, 0, 216, 0, 9, 0,
155, 0, 32, 0, 153, 0, 8, 0, 135, 0, 0, 2, 191, 128, 139, 2, 223, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0,
};
static s32 F152(DSPTaskInfo* task) {
s32 chan; // r31
GBAControl* gba; // r29
for (chan = 0; chan < 4; ++chan) {
gba = &__GBA[chan];
if (&gba->task == task) {
return chan;
}
}
ASSERT(0 <= chan && chan < 4);
OSPanic(__FILE__, 169, "GBA - unexpected dsp call");
return -1;
}
static void F23(void* task) {
s32 chan; // r31
GBAControl* gba; // r30
chan = F152(task);
gba = &__GBA[chan];
DSPSendMailToDSP(0xabba0000);
while (DSPCheckMailToDSP())
;
DSPSendMailToDSP((u32)gba->param);
while (DSPCheckMailToDSP())
;
}
void F25(void* task) {
s32 chan; // r31
chan = F152(task);
__GBAX01(chan, 0);
}
void __GBAX02(s32 chan, u8* readbuf) {
GBAControl* gba; // r28
GBABootInfo* bootInfo; // r29
GBASecParam* param; // r30
DSPTaskInfo* task; // r31
gba = &__GBA[chan];
bootInfo = &__GBA[chan].bootInfo;
param = gba->param;
memcpy(param, readbuf, 4);
param->paletteColor = bootInfo->paletteColor;
param->paletteSpeed = bootInfo->paletteSpeed;
param->length = bootInfo->length;
param->out = &param->keyA;
DCInvalidateRange(&param->keyA, 32);
DCFlushRange(param, 32);
task = &gba->task;
task->priority = 255;
task->iram_mmem_addr = (u16*)OSCachedToPhysical(D35);
task->iram_length = sizeof(D35);
task->iram_addr = 0;
task->dsp_init_vector = 16;
task->init_cb = F23;
task->res_cb = NULL;
task->done_cb = F25;
task->req_cb = NULL;
DSPAddTask(task);
}

View File

@ -1,6 +1,6 @@
#include "dolphin/GBAPriv.h"
void ReadProc(s32 chan) {
static void ReadProc(s32 chan) {
GBAControl* gba;
gba = &__GBA[chan];
@ -12,26 +12,24 @@ void ReadProc(s32 chan) {
s32 GBAReadAsync(s32 chan, u8* dst, u8* status, GBACallback callback) {
GBAControl* gba;
s32 ret;
gba = &__GBA[chan];
if (gba->callback != NULL) {
ret = 2;
} else {
return 2;
}
gba->output[0] = 0x14;
gba->ptr = dst;
gba->status = status;
gba->callback = callback;
ret = __GBATransfer(chan, 1, 5, ReadProc);
}
return ret;
return __GBATransfer(chan, 1, 5, ReadProc);
}
s32 GBARead(s32 chan, u8* dst, u8* status) {
s32 tmp;
GBAControl* gba = &__GBA[chan];
s32 ret;
ret = GBAReadAsync(chan, dst, status, __GBASyncCallback);
if (ret != GBA_READY) {

View File

@ -1,6 +1,6 @@
#include "dolphin/GBAPriv.h"
void WriteProc(s32 chan) {
static void WriteProc(s32 chan) {
GBAControl* gba;
gba = &__GBA[chan];
@ -12,28 +12,23 @@ void WriteProc(s32 chan) {
}
s32 GBAWriteAsync(s32 chan, u8* src, u8* status, GBACallback callback) {
GBAControl* gba;
s32 ret;
gba = &__GBA[chan];
GBAControl* gba = &__GBA[chan];
if (gba->callback != NULL) {
ret = GBA_BUSY;
} else {
return GBA_BUSY;
}
gba->output[0] = 0x15;
memcpy(&gba->output[1], src, 4);
gba->ptr = src;
gba->status = status;
gba->callback = callback;
ret = __GBATransfer(chan, 5, 1, WriteProc);
}
return ret;
return __GBATransfer(chan, 5, 1, WriteProc);
}
s32 GBAWrite(s32 chan, u8* src, u8* status) {
s32 ret;
s32 tmp;
GBAControl* gba = &__GBA[chan];
s32 ret;
ret = GBAWriteAsync(chan, src, status, __GBASyncCallback);
if (ret != GBA_READY) {
return ret;

View File

@ -1,7 +1,7 @@
#include "dolphin/GBAPriv.h"
#include "dolphin/sipriv.h"
void __GBAHandler(s32 chan, u32 error, OSContext* context) {
static void __GBAHandler(s32 chan, u32 error, OSContext* context) {
GBAControl* gba;
GBATransferCallback proc;
GBACallback callback;
@ -37,12 +37,15 @@ void __GBAHandler(s32 chan, u32 error, OSContext* context) {
OSSetCurrentContext(context);
}
void __GBASyncCallback(s32 chan, s32 ret) { OSWakeupThread(&__GBA[chan].threadQueue); }
void __GBASyncCallback(s32 chan, s32 ret) {
GBAControl* gba = &__GBA[chan];
OSWakeupThread(&gba->threadQueue);
}
s32 __GBASync(s32 chan) {
GBAControl* gba;
s32 enabled;
s32 ret;
s32 enabled;
gba = &__GBA[chan];
enabled = OSDisableInterrupts();
@ -57,40 +60,42 @@ s32 __GBASync(s32 chan) {
}
void TypeAndStatusCallback(s32 chan, u32 type) {
s32 tmp;
GBAControl* gba;
OSContext* context;
GBATransferCallback proc;
GBACallback callback;
GBATransferCallback xferCallback;
OSContext tmpContext;
OSContext exceptionContext;
OSContext* context;
gba = &__GBA[chan];
if (__GBAReset != 0) {
return;
}
ASSERT(!(type & SI_ERROR_BUSY));
if ((type & 0xFF) != 0 || (type & 0xffff0000) != 0x40000) {
gba->ret = GBA_NOT_READY;
} else {
if (SITransfer(chan, gba->output, gba->outputBytes, gba->input, gba->inputBytes, __GBAHandler, gba->delay)) {
if (SITransfer(chan, gba->output, gba->outputBytes, gba->input, gba->inputBytes, __GBAHandler,
gba->delay)) {
return;
}
gba->ret = GBA_BUSY;
}
if (gba->proc != NULL) {
xferCallback = gba->proc;
proc = gba->proc;
gba->proc = NULL;
xferCallback(chan);
proc(chan);
}
if (gba->callback != NULL) {
context = OSGetCurrentContext();
OSClearContext(&tmpContext);
OSSetCurrentContext(&tmpContext);
OSClearContext(&exceptionContext);
OSSetCurrentContext(&exceptionContext);
callback = gba->callback;
gba->callback = NULL;
callback(chan, gba->ret);
OSClearContext(&tmpContext);
OSClearContext(&exceptionContext);
OSSetCurrentContext(context);
__OSReschedule();
}

View File

@ -423,7 +423,7 @@ void hwFlushStream(void* base, unsigned long offset, unsigned long bytes, unsign
}
void hwPrepareStreamBuffer() {}
u32 hwInitStream(u32 len) { return aramAllocateStreamBuffer(len); }
u8 hwInitStream(u32 len) { return aramAllocateStreamBuffer(len); }
void hwExitStream(u8 id) { aramFreeStreamBuffer(id); }

670
src/musyx/runtime/seq.c Normal file
View File

@ -0,0 +1,670 @@
#include "musyx/seq.h"
#include "musyx/synth.h"
static NOTE seqNote[256];
SEQ_INSTANCE seqInstance[8];
u16 seqMIDIPriority[8][16];
static SEQ_INSTANCE* cseq = NULL;
static NOTE* noteFree = NULL;
static u32 curSeqId = 0;
static u8 curFadeOutState = 0;
static u32 seq_next_id = 0;
struct SEQ_INSTANCE* seqFreeRoot = NULL;
struct SEQ_INSTANCE* seqActiveRoot = NULL;
struct SEQ_INSTANCE* seqPausedRoot = NULL;
static void ClearNotes() {
NOTE* ln = NULL; // r30
s32 i; // r29
noteFree = &seqNote[0];
for (i = 0; i < 256; ++i) {
seqNote[i].prev = ln;
if (ln != NULL) {
ln->next = &seqNote[i];
}
ln = &seqNote[i];
}
ln->next = NULL;
}
static void ResetNotes(SEQ_INSTANCE* seq) {
NOTE* n; // r31
u32 i; // r30
for (i = 0; i < 2; ++i) {
n = seq->noteUsed[i];
if (n != NULL) {
for (; n->next != NULL; n = n->next) {
}
if (noteFree != NULL) {
n->next = noteFree;
noteFree->prev = n;
}
noteFree = seq->noteUsed[i];
seq->noteUsed[i] = NULL;
}
}
n = seq->noteKeyOff;
if (n != NULL) {
for (; n->next != NULL; n = n->next) {
}
if (noteFree != NULL) {
n->next = noteFree;
noteFree->prev = n;
}
noteFree = seq->noteKeyOff;
seq->noteKeyOff = NULL;
}
}
static void KillNotes(SEQ_INSTANCE* seq) {
NOTE* n; // r31
u32 i; // r30
for (i = 0; i < 2; ++i) {
for (n = seq->noteUsed[i]; n != NULL; n = n->next) {
voiceKillSound(n->id);
}
}
for (n = seq->noteKeyOff; n != NULL; n = n->next) {
voiceKillSound(n->id);
}
}
static NOTE* AllocateNote(u32 endTime, u8 section) {
NOTE* n; // r31
NOTE* nl; // r30
NOTE* last_nl; // r29
if ((n = noteFree) != NULL) {
if ((noteFree = n->next) != NULL) {
noteFree->prev = NULL;
}
n->endTime = endTime;
n->section = section;
n->timeIndex = cseq->section[section].timeIndex;
last_nl = NULL;
for (nl = cseq->noteUsed[n->timeIndex]; nl != NULL; nl = nl->next) {
if (nl->endTime > n->endTime) {
n->next = nl;
n->prev = last_nl;
if (last_nl != NULL) {
last_nl->next = n;
} else {
cseq->noteUsed[n->timeIndex] = n;
}
nl->prev = n;
return n;
}
last_nl = nl;
}
n->prev = last_nl;
if (last_nl != NULL) {
last_nl->next = n;
} else {
cseq->noteUsed[n->timeIndex] = n;
}
n->next = NULL;
}
return n;
}
static void FreeNote(struct NOTE* n) {
if (n->next != NULL) {
n->next->prev = n->prev;
}
if (n->prev != NULL) {
n->prev->next = n->next;
} else {
cseq->noteUsed[n->timeIndex] = n->next;
}
if ((n->next = noteFree) != NULL) {
noteFree->prev = n;
}
n->prev = NULL;
noteFree = n;
}
static u32 HandleNotes() {
NOTE* note; // r31
u32 i; // r30
for (i = 0; i < 2; ++i) {
note = cseq->noteUsed[i];
if (note != NULL) {
while (note->endTime <= cseq->section[note->section].time[i].high) {
synthSendKeyOff(note->id);
if ((cseq->noteUsed[i] = note->next) != NULL) {
cseq->noteUsed[i]->prev = NULL;
}
if ((note->next = cseq->noteKeyOff) != NULL) {
cseq->noteKeyOff->prev = note;
}
cseq->noteKeyOff = note;
note = cseq->noteUsed[i];
if (note == NULL) {
break;
}
}
}
}
return cseq->noteUsed[0] != NULL || cseq->noteUsed[1] != NULL;
}
static void KeyOffNotes() {
NOTE* note; // r31
NOTE* nextNote; // r29
u32 i; // r30
for (i = 0; i < 2; ++i) {
note = cseq->noteUsed[i];
while (note != NULL) {
nextNote = note->next;
synthSendKeyOff(note->id);
if ((cseq->noteUsed[i] = note->next) != NULL) {
cseq->noteUsed[i]->prev = NULL;
}
if ((note->next = cseq->noteKeyOff) != NULL) {
cseq->noteKeyOff->prev = note;
}
cseq->noteKeyOff = note;
note = nextNote;
}
}
}
static void seqFreeKeyOffNote(NOTE* n) {
if (n->next != NULL) {
n->next->prev = n->prev;
}
if (n->prev != NULL) {
n->prev->next = n->next;
} else {
cseq->noteKeyOff = n->next;
}
if ((n->next = noteFree) != NULL) {
noteFree->prev = n;
}
n->prev = NULL;
noteFree = n;
}
static void HandleKeyOffNotes() {
NOTE* n; // r31
NOTE* nn; // r30
if (!cseq->keyOffCheck) {
n = cseq->noteKeyOff;
while (n != NULL) {
nn = n->next;
if (n->id != -1 && sndFXCheck(n->id) == -1) {
seqFreeKeyOffNote(n);
}
n = nn;
}
}
cseq->keyOffCheck = (cseq->keyOffCheck + 1) % 5;
}
static void InitPublicIds() { seq_next_id = 0; }
static u32 GetPublicId(u32 seqId) {
u32 pub_id; // r30
SEQ_INSTANCE* si; // r31
si = &seqInstance[seqId];
}
u32 seqGetPrivateId(u32 seqId) {
SEQ_INSTANCE* si; // r31
}
static void DoPrgChange(SEQ_INSTANCE* seq, u8 prg, u8 midi) {
seqMIDIPriority[curSeqId][midi] = 0xFFFF;
if (midi != 9) {
prg = seq->normTrans[prg];
if (prg == 0xFF) {
return;
}
seq->prgState[midi].macId = seq->normtab[prg].macro;
seq->prgState[midi].priority = seq->normtab[prg].prio;
seq->prgState[midi].maxVoices = seq->normtab[prg].maxVoices;
return;
}
prg = seq->drumTrans[prg];
if (prg == 0xFF) {
return;
}
seq->prgState[midi].macId = seq->drumtab[prg].macro;
seq->prgState[midi].priority = seq->drumtab[prg].prio;
seq->prgState[midi].maxVoices = seq->drumtab[prg].maxVoices;
}
static void BuildTransTab(u8* tab, PAGE* page) {
u8 i; // r31
for (i = 0; i < 128; ++i) {
tab[i] = 0xff;
}
for (i = 0; page->index != 0xFF; ++i, ++page) {
tab[page->index] = i;
}
}
u32 seqStartPlay(PAGE* norm, PAGE* drum, MIDISETUP* midiSetup, u32* song, SND_PLAYPARA* para,
u8 studio, u16 sgid) {
ARR* arr; // r27
u32* tracktab; // r24
s32 i; // r31
SEQ_INSTANCE* nseq; // r30
SEQ_INSTANCE* oldCSeq; // r23
u32 seqId; // r28
u32 bpm; // r25
if ((nseq = seqFreeRoot) == NULL) {
return -1;
};
if ((seqFreeRoot = seqFreeRoot->next) != NULL) {
seqFreeRoot->prev = NULL;
}
if ((nseq->next = seqActiveRoot) != NULL) {
seqActiveRoot->prev = nseq;
}
nseq->prev = NULL;
seqActiveRoot = nseq;
nseq->state = 1;
for (i = 0; i < 16; ++i) {
nseq->section[i].globalEventRoot = NULL;
}
seqId = nseq->index;
nseq->syncActive = FALSE;
nseq->normtab = norm;
nseq->drumtab = drum;
nseq->arrbase = (ARR*)song;
nseq->groupID = sgid;
BuildTransTab(nseq->normTrans, nseq->normtab);
BuildTransTab(nseq->drumTrans, nseq->drumtab);
nseq->defVGroup = seqId + 23;
for (i = 0; i < 64; ++i) {
nseq->trackVolGroup[i] = nseq->defVGroup;
}
nseq->defStudio = studio;
if (para == NULL) {
nseq->trackMute[0] = -1;
nseq->trackMute[1] = -1;
for (i = 0; i < 16; ++i) {
nseq->section[i].speed = 256;
}
synthVolume(127, 0, nseq->defVGroup, 0, -1);
} else {
if (para->flags & SND_PLAYPARA_TRACKMUTE) {
nseq->trackMute[0] = para->trackMute[0];
nseq->trackMute[1] = para->trackMute[1];
} else {
nseq->trackMute[0] = -1;
nseq->trackMute[1] = -1;
}
if (para->flags & SND_PLAYPARA_SPEED) {
for (i = 0; i < 16; ++i) {
nseq->section[i].speed = para->speed;
}
} else {
for (i = 0; i < 16; ++i) {
nseq->section[i].speed = 256;
}
}
if (para->flags & SND_PLAYPARA_SEQVOLDEF) {
for (i = 0; i < para->numSeqVolDef; ++i) {
nseq->trackVolGroup[para->seqVolDef[i].track] = para->seqVolDef[i].volGroup;
synthSetMusicVolumeType(para->seqVolDef[i].volGroup, 0);
}
}
if (para->flags & SND_PLAYPARA_VOLUME) {
synthVolume(para->volume.target, para->volume.time, nseq->defVGroup, 0, -1);
for (i = 0; i < para->numFaded; ++i) {
synthVolume(para->volume.target, para->volume.time, para->faded[i], 0, -1);
}
}
}
arr = (ARR*)song;
if (arr->info & 0x80000000) {
nseq->trackSectionTab = (u8*)(arr->tsTab + (u32)arr);
} else {
nseq->trackSectionTab = NULL;
}
bpm = arr->info & 0x0fffffff;
if (!(arr->info & 0x40000000)) {
bpm <<= 10;
}
for (i = 0; i < 16; ++i) {
nseq->section[i].bpm = bpm;
synthSetBpm(bpm >> 10, seqId & 0xFF, i & 0xFF);
if (arr->mTrack != NULL) {
nseq->section[i].mTrack.base = (MTRACK_DATA*)(arr->mTrack + (u32)arr);
nseq->section[i].mTrack.addr = nseq->section[i].mTrack.base;
} else {
nseq->section[i].mTrack.base = NULL;
}
nseq->section[i].loopDisable = FALSE;
nseq->section[i].loopCnt = 0;
}
tracktab = &arr->tTab;
for (i = 0; i < 64; ++i) {
synthTrackVolume[i] = 127;
nseq->pattern[i].addr = NULL;
// TODO: Finish
}
return -1;
}
static void SetTickDelta(SEQ_SECTION* section, u32 deltaTime) {
float tickDelta = (float)section->bpm * (float)deltaTime * 0.0000000244140619f;
tickDelta *= section->speed * 0.00390625f;
section->tickDelta[section->timeIndex].low = fmodf(tickDelta * 65536.f, 65536.f);
section->tickDelta[section->timeIndex].high = floorf(tickDelta);
}
static void HandleMasterTrack(u8 secIndex) {
SEQ_SECTION* section; // r31
section = &cseq->section[secIndex];
if (section->mTrack.base == NULL) {
return;
}
while (section->mTrack.addr->time != -1) {
if (section->mTrack.addr->time > section->time[section->timeIndex].high) {
break;
}
if (cseq->arrbase->info & 0x40000000) {
synthSetBpm((section->bpm = section->mTrack.addr->bpm) >> 10, curSeqId, secIndex);
} else {
synthSetBpm(section->mTrack.addr->bpm, curSeqId, secIndex);
section->bpm = section->mTrack.addr->bpm << 10;
}
++section->mTrack.addr;
}
}
static void RewindMTrack(unsigned char secIndex, unsigned long deltaTime) {
if (cseq->section[secIndex].mTrack.base == NULL) {
return;
}
cseq->section[secIndex].mTrack.addr = cseq->section[secIndex].mTrack.base;
HandleMasterTrack(secIndex);
SetTickDelta(cseq->section + secIndex, deltaTime);
}
static void StartPause(SEQ_INSTANCE* si) {
if (si->prev != NULL) {
si->prev->next = si->next;
} else {
seqActiveRoot = si->next;
}
if (si->next != NULL) {
si->next->prev = si->prev;
}
if ((si->next = seqPausedRoot) != NULL) {
seqPausedRoot->prev = si;
}
si->prev = NULL;
seqPausedRoot = si;
si->state = 2;
}
void seqPause(u32 seqId) {
SEQ_INSTANCE* si; // r31
seqId = seqGetPrivateId(seqId);
if (seqId == -1) {
return;
}
if (!(seqId & 0x80000000)) {
si = &seqInstance[seqId];
if (si->state == 1) {
StartPause(si);
KillNotes(si);
ResetNotes(si);
}
} else {
si = &seqInstance[seqId & 0x7fffffff];
if (si->state != 0) {
si->syncCrossInfo.flags |= 8;
}
}
}
void seqStop(unsigned long seqId) {
SEQ_INSTANCE* si; // r31
;
if ((seqId = seqGetPrivateId(seqId)) == -1) {
return;
}
if (!(seqId & 0x80000000)) {
si = &seqInstance[seqId];
switch (si->state) {
case 1:
if (si->prev != NULL) {
si->prev->next = si->next;
} else {
seqActiveRoot = si->next;
}
KillNotes(&seqInstance[seqId]);
ResetNotes(&seqInstance[seqId]);
break;
case 2:
if (si->prev != NULL) {
si->prev->next = si->next;
} else {
seqPausedRoot = si->next;
}
break;
}
if (si->next != NULL) {
si->next->prev = si->prev;
}
si->state = 0;
if (seqFreeRoot != NULL) {
seqFreeRoot->prev = si;
}
si->next = seqFreeRoot;
si->prev = NULL;
seqFreeRoot = si;
} else {
si = &seqInstance[seqId & 0x7fffffff];
if (si->state != 0) {
si->syncSeqIdPtr = NULL;
}
}
}
void seqKillAllInstances() {
SEQ_INSTANCE* si; // r31
for (si = seqActiveRoot; si != NULL; si = si->next) {
seqStop(si->publicId);
}
for (si = seqPausedRoot; si != NULL; si = si->next) {
seqStop(si->publicId);
}
}
void seqKillInstancesByGroupID(unsigned short sgid) {
SEQ_INSTANCE* si; // r31
for (si = seqActiveRoot; si != NULL; si = si->next) {
if (si->groupID == sgid) {
seqStop(si->publicId);
}
}
for (si = seqPausedRoot; si != NULL; si = si->next) {
if (si->groupID == sgid) {
seqStop(si->publicId);
}
}
}
void seqSpeed(unsigned long seqId, unsigned short speed) {
u32 i; // r30
seqId = seqGetPrivateId(seqId);
MUSY_ASSERT_MSG(seqId != -1, "Sequencer ID is not valid.");
if (!(seqId & 0x80000000)) {
for (i = 0; i < 16; ++i) {
seqInstance[seqId].section[i].speed = speed;
}
} else {
seqId &= 0x7FFFFFFF;
seqInstance[seqId].syncCrossInfo.flags |= 0x20;
seqInstance[seqId].syncCrossInfo.speed2 = speed;
}
}
void seqContinue(u32 seqId) {
struct SEQ_INSTANCE* si; // r31
seqId = seqGetPrivateId(seqId);
MUSY_ASSERT_MSG(seqId != -1, "Sequencer ID is not valid.");
if (!(seqId & 0x80000000)) {
si = &seqInstance[seqId];
if (si->state == 2) {
if (si->prev != NULL) {
si->prev->next = si->next;
} else {
seqPausedRoot = si->next;
}
if (si->next != NULL) {
si->next->prev = si->prev;
}
if ((si->next = seqActiveRoot) != NULL) {
seqActiveRoot->prev = si;
}
si->prev = NULL;
seqActiveRoot = si;
si->state = 1;
}
} else {
seqInstance[seqId & 0x7FFFFFFF].syncCrossInfo.flags &= ~0x8;
}
}
void seqMute(unsigned long seqId, unsigned long mask1, unsigned long mask2) {
seqId = seqGetPrivateId(seqId);
if (seqId == 0xffffffff) {
return;
}
if (!(seqId & 0x80000000)) {
seqInstance[seqId].trackMute[0] = mask1;
seqInstance[seqId].trackMute[1] = mask2;
} else {
seqId &= 0x7fffffff;
seqInstance[seqId].syncCrossInfo.flags |= 0x10;
seqInstance[seqId].syncCrossInfo.trackMute2[0] = mask1;
seqInstance[seqId].syncCrossInfo.trackMute2[1] = mask2;
}
}
void seqVolume(unsigned char volume, unsigned short time, unsigned long seqId, unsigned char mode) {
unsigned long i; // r29
unsigned long pub_id; // r27
pub_id = seqId;
seqId = seqGetPrivateId(seqId);
if (seqId == -1) {
return;
}
if (!(seqId & 0x80000000)) {
synthVolume(volume, time, seqInstance[seqId].defVGroup, mode, pub_id);
for (i = 0; i < 64; ++i) {
if (seqInstance[seqId].trackVolGroup[i] != seqInstance[seqId].defVGroup) {
synthVolume(volume, time, seqInstance[seqId].trackVolGroup[i], 0, -1);
}
}
} else {
seqId &= 0x7fffffff;
switch (mode & 0xf) {
case 0:
seqInstance[seqId].syncCrossInfo.vol2 = volume;
break;
case 1:
seqInstance[seqId].syncSeqIdPtr = NULL;
break;
case 2:
seqInstance[seqId].syncCrossInfo.flags |= 8;
seqInstance[seqId].syncCrossInfo.vol2 = volume;
break;
case 3:
seqInstance[seqId].syncCrossInfo.flags |= 0x80;
seqInstance[seqId].syncCrossInfo.vol2 = volume;
break;
default:
MUSY_FATAL("Illegal sequencere fade mode detected.");
break;
}
}
}

View File

@ -1,58 +1,462 @@
#include "musyx/musyx_priv.h"
#include "musyx/synth.h"
#ifndef _DEBUG
#include "dolphin/os.h"
#endif
SND_STREAM_INFO streamInfo[64];
u32 nextPublicID = 0;
u8 streamCallDelay = 0;
static STREAM_INFO streamInfo[64];
u8 streamCallCnt = 0;
u8 streamCallDelay = 0;
u32 nextPublicID = 0;
void streamInit() {
s32 i;
streamCallCnt = 0;
streamCallDelay = 3;
for (i = 0; i < synthInfo.voices; ++i) {
streamInfo[i].xc_ = 0;
for (i = 0; i < synthInfo.voiceNum; ++i) {
streamInfo[i].state = 0;
}
nextPublicID = 0;
}
void SetHWMix(SND_STREAM_INFO* info) {
// hwSetVolume()
#if MUSY_VERSION >= MUSY_VERSION_CHECK(1, 5, 4)
void SetHWMix(const STREAM_INFO* si) {
hwSetVolume(si->voice, 0, si->vol * (1 / 127.f), (si->pan << 16), (si->span << 16),
si->auxa * (1 / 127.f), si->auxb * (1 / 127.f));
}
#endif
void streamHandle() {}
void streamHandle() {
u32 i; // r25
u32 cpos; // r30
u32 len; // r29
struct SAMPLE_INFO newsmp; // r1+0x8
struct STREAM_INFO* si; // r31
float f; // r63
// TODO: Match this
}
void streamCorrectLoops() {}
void streamKill(SND_STREAMID streamId) {
SND_STREAM_INFO* stream = &streamInfo[streamId];
switch (stream->xc_) {
void streamKill(u32 voice) {
STREAM_INFO* si = &streamInfo[voice];
switch (si->state) {
case 1:
case 2:
if (stream->xc_ == 2) {
voiceUnblock(stream->voiceId);
if (si->state == 2) {
voiceUnblock(si->voice);
}
stream->xc_ = 3;
stream->updateCb(NULL, 0, NULL, 0, stream->user);
si->state = 3;
si->updateFunction(NULL, 0, NULL, 0, (void*)si->user);
break;
default:
break;
}
}
s32 GetPrivateIndex(s32 something) {
s32 i;
static u32 GetPrivateIndex(u32 publicID) {
u32 i; // r31
for (i = 0; i < 64; ++i) {
if (streamInfo[i].xc_ != 0 && something == streamInfo[i].x4_) {
if (streamInfo[i].state != 0 && publicID == streamInfo[i].stid) {
return i;
}
}
return -1;
}
void sndStreamARAMUpdate() {
static u32 GeneratePublicID() {
u32 id; // r30
u32 i; // r31
do {
if ((id = nextPublicID++) == -1) {
id = nextPublicID;
nextPublicID = id + 1;
}
for (i = 0; i < 64; ++i) {
if (streamInfo[i].state != 0 && id == streamInfo[i].stid) {
break;
}
}
} while (i != 64);
return id;
}
u32 sndStreamCallbackFrq(u32 msTime) {
s32 time; // r31
time = ((msTime * 2 + 5) / 10) - 1;
streamCallDelay = time < 0 ? 0 : time;
return (streamCallDelay + 1) * 5;
}
void sndStreamARAMUpdate(u32 stid, u32 off1, u32 len1, u32 off2, u32 len2) {
u32 i; // r30
MUSY_ASSERT_MSG(sndActive, "Sound system is not initialized.");
hwDisableIrq();
i = GetPrivateIndex(stid);
if (i != -1) {
switch (streamInfo[i].type) {
case 0:
off1 *= 2;
len1 *= 2;
off2 *= 2;
len2 *= 2;
break;
case 1:
off1 = (off1 / 14) * 8;
len1 = ((len1 + 13) / 14) * 8;
off2 = (off2 / 14) * 8;
len2 = ((len2 + 13) / 14) * 8;
break;
}
if (len1 != 0) {
hwFlushStream(streamInfo[i].buffer, off1, len1, streamInfo[i].hwStreamHandle, 0, 0);
}
if (len2 != 0) {
hwFlushStream(streamInfo[i].buffer, off2, len2, streamInfo[i].hwStreamHandle, 0, 0);
}
#if MUSY_VERSION >= MUSY_VERSION_CHECK(1, 5, 4)
if (streamInfo[i].type == 1) {
streamInfo[i].lastPSFromBuffer = (*(u32*)OSCachedToUncached(streamInfo[i].buffer)) >> 24;
if (streamInfo[i].voice != -1) {
hwSetStreamLoopPS(streamInfo[i].voice, streamInfo[i].lastPSFromBuffer);
}
}
#else
if (streamInfo[i].type == 1) {
hwSetStreamLoopPS(streamInfo[i].voice, *(u32*)OSCachedToUncached(streamInfo[i].buffer) >> 24);
}
#endif
} else {
MUSY_DEBUG("ID is invalid.\n");
}
hwEnableIrq();
}
static void CheckOutputMode(u8* pan, u8* span) {
if (synthFlags & 1) {
*pan = 64;
*span = 0;
} else if (!(synthFlags & 2)) {
*span = 0;
}
}
#if MUSY_VERSION >= MUSY_VERSION_CHECK(1, 5, 4)
static void SetupVolumeAndPan(STREAM_INFO* si, u8 vol, u8 pan, u8 span, u8 auxa, u8 auxb) {
si->orgPan = pan;
si->orgSPan = span;
CheckOutputMode(&pan, &span);
si->vol = vol;
si->pan = pan;
si->span = span;
si->auxa = auxa;
si->auxb = auxb;
}
#endif
u32 sndStreamAllocEx(u8 prio, void* buffer, u32 samples, u32 frq, u8 vol, u8 pan, u8 span, u8 auxa,
u8 auxb, u8 studio, u32 flags, SND_STREAM_UPDATE_CALLBACK updateFunction,
u32 user, SND_ADPCMSTREAM_INFO* adpcmInfo) {
u32 stid; // r29
u32 i; // r31
u32 bytes; // r25
u32 j; // r28
MUSY_ASSERT_MSG(sndActive, "Sound system is not initialized.");
hwDisableIrq();
for (i = 0; i < 64; ++i) {
if (streamInfo[i].state == 0) {
break;
}
}
if (i != 64) {
stid = GeneratePublicID();
streamInfo[i].stid = stid;
streamInfo[i].flags = flags;
bytes = sndStreamAllocLength(samples, flags);
streamInfo[i].buffer = (s16*)buffer;
streamInfo[i].size = samples;
streamInfo[i].bytes = bytes;
streamInfo[i].updateFunction = updateFunction;
streamInfo[i].voice = -1;
if (flags & 1) {
if (adpcmInfo != NULL) {
for (j = 0; j < 8; j++) {
streamInfo[i].adpcmInfo.coefTab[j][0] = adpcmInfo->coefTab[j][0];
streamInfo[i].adpcmInfo.coefTab[j][1] = adpcmInfo->coefTab[j][1];
}
streamInfo[i].adpcmInfo.numCoef = 8;
}
streamInfo[i].type = 1;
} else {
streamInfo[i].type = 0;
}
streamInfo[i].frq = frq;
streamInfo[i].studio = studio;
streamInfo[i].prio = prio;
#if MUSY_VERSION <= MUSY_VERSION_CHECK(1, 5, 3)
CheckOutputMode(&pan, &span);
streamInfo[i].vol = vol;
streamInfo[i].pan = pan;
streamInfo[i].span = span;
streamInfo[i].auxa = auxa;
streamInfo[i].auxb = auxb;
#else
SetupVolumeAndPan(&streamInfo[i], vol, pan, span, auxa, auxb);
#endif
streamInfo[i].user = user;
streamInfo[i].nextStreamHandle = -1;
streamInfo[i].state = 3;
if ((streamInfo[i].hwStreamHandle = hwInitStream(bytes)) != 0xFF) {
if (!(flags & 0x10000) && !sndStreamActivate(stid)) {
MUSY_DEBUG("No voice could be allocated for streaming.\n");
stid = -1;
}
} else {
MUSY_DEBUG("No ARAM memory could be allocated for streaming.\n");
stid = -1;
}
if (stid == -1) {
streamInfo[i].state = 0;
}
} else {
stid = -1;
}
hwEnableIrq();
return stid;
}
u32 sndStreamAllocStereo(u8 prio, void* lBuffer, void* rBuffer, u32 samples, u32 frq, u8 vol,
u8 pan, u8 span, u8 auxa, u8 auxb, u8 studio, u32 flags,
SND_STREAM_UPDATE_CALLBACK updateFunction, u32 lUser, u32 rUser,
SND_ADPCMSTREAM_INFO* adpcmInfoL, SND_ADPCMSTREAM_INFO* adpcmInfoR) {
u32 stid[2]; // r1+0x38
s16 rPan; // r31
s16 lPan; // r30
lPan = pan - 64;
lPan = lPan < 0 ? 0 : lPan > 127 ? 127 : lPan;
rPan = pan + 64;
rPan = rPan < 0 ? 0 : rPan > 127 ? 127 : rPan;
hwDisableIrq();
;
if ((stid[0] = sndStreamAllocEx(prio, lBuffer, samples, frq, vol, lPan, span, auxa, auxb, studio,
flags, updateFunction, lUser, adpcmInfoL)) != 0xFFFFFFFF) {
if ((stid[1] = sndStreamAllocEx(prio, rBuffer, samples, frq, vol, rPan, span, auxa, auxb,
studio, flags, updateFunction, rUser, adpcmInfoR)) ==
0xFFFFFFFF) {
sndStreamFree(stid[0]);
hwEnableIrq();
return 0xFFFFFFFF;
}
streamInfo[GetPrivateIndex(stid[0])].nextStreamHandle = stid[1];
}
hwEnableIrq();
return stid[0];
}
u32 sndStreamAllocLength(u32 num, u32 flags) {
if (flags & 1) {
return (((num + 13) / 14) * 8 + 31) & ~31;
}
return (num * 2 + 31) & ~31;
}
void sndStreamADPCMParameter(u32 stid, SND_ADPCMSTREAM_INFO* adpcmInfo) {
u32 j; // r31
u32 i; // r30
MUSY_ASSERT_MSG(sndActive, "Sound system is not initialized.");
hwDisableIrq();
i = GetPrivateIndex(stid);
if (i != -1) {
for (j = 0; j < 8; ++j) {
streamInfo[i].adpcmInfo.coefTab[j][0] = adpcmInfo->coefTab[j][0];
streamInfo[i].adpcmInfo.coefTab[j][1] = adpcmInfo->coefTab[j][1];
}
streamInfo[i].adpcmInfo.numCoef = 8;
if (streamInfo[i].nextStreamHandle != 0xffffffff) {
sndStreamADPCMParameter(streamInfo[i].nextStreamHandle, adpcmInfo);
}
} else {
MUSY_DEBUG("ID is invalid.\n");
}
hwEnableIrq();
}
void sndStreamMixParameter(u32 stid, u8 vol, u8 pan, u8 span, u8 fxvol) {
u32 i; // r31
MUSY_ASSERT_MSG(sndActive, "Sound system is not initialized.");
hwDisableIrq();
i = GetPrivateIndex(stid);
if (i != -1) {
#if MUSY_VERSION < MUSY_VERSION_CHECK(1, 5, 4)
CheckOutputMode(&pan, &span);
streamInfo[i].vol = vol;
streamInfo[i].pan = pan;
streamInfo[i].span = span;
streamInfo[i].auxa = fxvol;
streamInfo[i].auxb = 0;
hwSetVolume(streamInfo[i].voice, 0, vol * (1 / 127.f), (pan << 16), (span << 16),
fxvol * (1 / 127.f), 0.f);
#else
SetupVolumeAndPan(&streamInfo[i], vol, pan, span, fxvol, 0);
SetHWMix(&streamInfo[i]);
#endif
if (streamInfo[i].nextStreamHandle != -1) {
sndStreamMixParameter(streamInfo[i].nextStreamHandle, vol, pan, span, fxvol);
}
} else {
MUSY_DEBUG("ID is invalid.\n");
}
hwEnableIrq();
}
void sndStreamMixParameterEx(u32 stid, u8 vol, u8 pan, u8 span, u8 auxa, u8 auxb) {
u32 i; // r31
MUSY_ASSERT_MSG(sndActive, "Sound system is not initialized.");
hwDisableIrq();
i = GetPrivateIndex(stid);
if (i != -1) {
#if MUSY_VERSION <= MUSY_VERSION_CHECK(1, 5, 3)
streamInfo[i].vol = vol;
streamInfo[i].pan = pan;
streamInfo[i].span = span;
streamInfo[i].auxa = fxvol;
streamInfo[i].auxb = 0;
if (streamInfo[i].state == 2) {
hwSetVolume(streamInfo[i].voice, 0, vol * (1 / 127.f), (pan << 16), (span << 16),
auxa * (1 / 127.f), auxb * (1 / 127.f));
}
#else
SetupVolumeAndPan(&streamInfo[i], vol, pan, span, auxa, auxb);
if (streamInfo[i].state == 2) {
SetHWMix(&streamInfo[i]);
}
#endif
if (streamInfo[i].nextStreamHandle != -1) {
sndStreamMixParameterEx(streamInfo[i].nextStreamHandle, vol, pan, span, auxa, auxb);
}
} else {
MUSY_DEBUG("ID is invalid.\n");
}
hwEnableIrq();
}
void sndStreamFrq(u32 stid, u32 frq) {
u32 i; // r31
u16 pitch; // r27
MUSY_ASSERT_MSG(sndActive, "Sound system is not initialized.");
hwDisableIrq();
i = GetPrivateIndex(stid);
if (i != -1) {
streamInfo[i].frq = frq;
if (streamInfo[i].state == 2) {
pitch = (4096.f * frq) / synthInfo.mixFrq;
hwSetPitch(streamInfo[i].voice, pitch);
}
if (streamInfo[i].nextStreamHandle != -1) {
sndStreamFrq(streamInfo[i].nextStreamHandle, frq);
}
} else {
MUSY_DEBUG("ID is invalid.\n");
}
hwEnableIrq();
}
void sndStreamFree(u32 stid) {
u32 i; // r31
MUSY_ASSERT_MSG(sndActive, "Sound system is not initialized.");
hwDisableIrq();
i = GetPrivateIndex(stid);
if (i != -1) {
sndStreamDeactivate(stid);
hwExitStream(streamInfo[i].hwStreamHandle);
if (streamInfo[i].nextStreamHandle != -1) {
sndStreamFree(streamInfo[i].nextStreamHandle);
}
streamInfo[i].state = 0;
} else {
MUSY_DEBUG("ID is invalid.\n");
}
hwEnableIrq();
}
u32 sndStreamActivate(u32 stid) {
u32 i; // r31
u32 ret; // r28
ret = 0;
MUSY_ASSERT_MSG(sndActive, "Sound system is not initialized.");
hwDisableIrq();
i = GetPrivateIndex(stid);
if (i != -1) {
if (streamInfo[i].state == 3) {
if ((streamInfo[i].voice = voiceBlock(streamInfo[i].prio)) == -1) {
MUSY_DEBUG("No voice could be allocated for streaming.\n");
hwEnableIrq();
return 0;
}
streamInfo[i].last = 0;
streamInfo[i].state = 1;
} else {
MUSY_DEBUG("Stream is already active.\n");
}
if (streamInfo[i].nextStreamHandle != -1) {
ret = sndStreamActivate(streamInfo[i].nextStreamHandle);
} else {
ret = 1;
}
} else {
MUSY_DEBUG("ID is invalid.\n");
}
hwEnableIrq();
return ret;
}
void sndStreamDeactivate(u32 stid) {
u32 i; // r31
MUSY_ASSERT_MSG(sndActive, "Sound system is not initialized.");
hwDisableIrq();
i = GetPrivateIndex(stid);
if (i != -1) {
if (streamInfo[i].state == 1 || streamInfo[i].state == 2) {
voiceUnblock(streamInfo[i].voice);
streamInfo[i].state = 3;
}
if (streamInfo[i].nextStreamHandle != -1) {
sndStreamDeactivate(streamInfo[i].nextStreamHandle);
}
} else {
MUSY_DEBUG("ID is invalid.\n");
}
hwEnableIrq();
}

View File

@ -618,6 +618,7 @@ static void mcmdSetADSRFromCtrl(SYNTH_VOICE* svoice, MSTEP* cstep) {
float sScale; // r63
ADSR_INFO adsr; // r1+0x10
}
static void mcmdSetPitchADSR(SYNTH_VOICE* svoice, MSTEP* cstep) {
ADSR_INFO adsr; // r1+0x10
ADSR_INFO* adsr_ptr; // r31
@ -625,6 +626,7 @@ static void mcmdSetPitchADSR(SYNTH_VOICE* svoice, MSTEP* cstep) {
s32 ascale; // r27
s32 dscale; // r26
}
static u32 mcmdPitchSweep(SYNTH_VOICE* svoice, MSTEP* cstep, int num) {
s32 delta; // r31
svoice->sweepOff[num] = 0;
@ -692,7 +694,7 @@ static u32 TranslateVolume(u32 volume, u16 curve) {
if (vhigh < 0x7f) {
d = vlow * (ptr[vhigh + 1] - ptr[vhigh]);
volume = d + (ptr[vhigh] << 16);
volume = d + ((u8)ptr[vhigh] << 16);
} else {
volume = ptr[vhigh] << 16;
}
@ -793,6 +795,7 @@ static void mcmdRandomKey(SYNTH_VOICE* svoice, MSTEP* cstep) {
s32 i2; // r27
u8 detune; // r26
}
static void mcmdSetPitchbendAfterKeyOff(SYNTH_VOICE* svoice) { svoice->cFlags |= 0x10000; }
static void mcmdScaleReverb(SYNTH_VOICE* svoice, MSTEP* cstep) {
svoice->revVolScale = (u8)(cstep->para[0] >> 8);
@ -1073,6 +1076,7 @@ static void mcmdGetMessage(SYNTH_VOICE* svoice, MSTEP* cstep) {
}
varSet32(svoice, 0, (u8)(cstep->para[0] >> 8), mesg);
}
static void mcmdGetVID(SYNTH_VOICE* svoice, MSTEP* cstep) {
if ((u8)(cstep->para[0] >> 0x10) == 0) {
varSet32(svoice, 0, (u8)(cstep->para[0] >> 8), svoice->vidList->vid);

View File

@ -299,9 +299,7 @@ u32 voiceAllocate(u8 priority, u8 maxVoices, u16 allocId, u8 fxFlag) {
void voiceFree(SYNTH_VOICE* svoice) {
u32 i; // r29
SYNTH_VOICELIST* sfv; // r30
#line 628
MUSY_ASSERT(svoice->id != 0xFFFFFFFF);
#line 256
macMakeInactive(svoice, MAC_STATE_STOPPED);
voiceRemovePriority(svoice);
svoice->addr = NULL;
@ -413,11 +411,11 @@ long voiceKillSound(u32 voiceid) {
u32 next_voiceid; // r28
u32 i; // r30
if (sndActive != FALSE) {
for (i = vidGetInternalId(voiceid); i != 0xFFFFFFFF; i = next_voiceid) {
voiceid = (u8)i;
next_voiceid = synthVoice[voiceid].child;
if (i == synthVoice[voiceid].id) {
voiceKill(voiceid);
for (voiceid = vidGetInternalId(voiceid); voiceid != -1; voiceid = next_voiceid) {
i = voiceid & 0xff;
next_voiceid = synthVoice[i].child;
if (voiceid == synthVoice[i].id) {
voiceKill(i);
ret = 0;
}
}