MusyX progress

This commit is contained in:
Phillip Stephens 2023-02-24 09:42:08 -08:00
parent cbe676015f
commit 5096cbf77b
13 changed files with 1356 additions and 157 deletions

View File

@ -380,7 +380,7 @@ lbl_803B13B4:
/* 803B13D4 003AE334 93 63 02 14 */ stw r27, 0x214(r3) /* 803B13D4 003AE334 93 63 02 14 */ stw r27, 0x214(r3)
/* 803B13D8 003AE338 80 0D AE 78 */ lwz r0, synthVoice@sda21(r13) /* 803B13D8 003AE338 80 0D AE 78 */ lwz r0, synthVoice@sda21(r13)
/* 803B13DC 003AE33C 7C 60 CA 14 */ add r3, r0, r25 /* 803B13DC 003AE33C 7C 60 CA 14 */ add r3, r0, r25
/* 803B13E0 003AE340 4B FE 97 01 */ bl synthkeystateupdate /* 803B13E0 003AE340 4B FE 97 01 */ bl synthKeyStateUpdate
lbl_803B13E4: lbl_803B13E4:
/* 803B13E4 003AE344 3B 39 04 04 */ addi r25, r25, 0x404 /* 803B13E4 003AE344 3B 39 04 04 */ addi r25, r25, 0x404
/* 803B13E8 003AE348 3B 9C 00 01 */ addi r28, r28, 1 /* 803B13E8 003AE348 3B 9C 00 01 */ addi r28, r28, 1
@ -590,7 +590,7 @@ lbl_803B169C:
/* 803B16BC 003AE61C 93 83 02 14 */ stw r28, 0x214(r3) /* 803B16BC 003AE61C 93 83 02 14 */ stw r28, 0x214(r3)
/* 803B16C0 003AE620 80 0D AE 78 */ lwz r0, synthVoice@sda21(r13) /* 803B16C0 003AE620 80 0D AE 78 */ lwz r0, synthVoice@sda21(r13)
/* 803B16C4 003AE624 7C 60 CA 14 */ add r3, r0, r25 /* 803B16C4 003AE624 7C 60 CA 14 */ add r3, r0, r25
/* 803B16C8 003AE628 4B FE 94 19 */ bl synthkeystateupdate /* 803B16C8 003AE628 4B FE 94 19 */ bl synthKeyStateUpdate
lbl_803B16CC: lbl_803B16CC:
/* 803B16CC 003AE62C 3B 39 04 04 */ addi r25, r25, 0x404 /* 803B16CC 003AE62C 3B 39 04 04 */ addi r25, r25, 0x404
/* 803B16D0 003AE630 3B BD 00 01 */ addi r29, r29, 1 /* 803B16D0 003AE630 3B BD 00 01 */ addi r29, r29, 1

View File

@ -110,7 +110,7 @@ inpAuxB:
.skip 0x480 .skip 0x480
.global inpAuxA .global inpAuxA
inpAuxA: inpAuxA:
.skip 0x484 .skip 0x480
.section .sbss .section .sbss
.balign 8 .balign 8
@ -2289,8 +2289,8 @@ synthForceLowPrecisionUpdate:
/* 8039AAD8 00397A38 38 21 00 10 */ addi r1, r1, 0x10 /* 8039AAD8 00397A38 38 21 00 10 */ addi r1, r1, 0x10
/* 8039AADC 00397A3C 4E 80 00 20 */ blr /* 8039AADC 00397A3C 4E 80 00 20 */ blr
.global synthkeystateupdate .global synthKeyStateUpdate
synthkeystateupdate: synthKeyStateUpdate:
/* 8039AAE0 00397A40 94 21 FF F0 */ stwu r1, -0x10(r1) /* 8039AAE0 00397A40 94 21 FF F0 */ stwu r1, -0x10(r1)
/* 8039AAE4 00397A44 7C 08 02 A6 */ mflr r0 /* 8039AAE4 00397A44 7C 08 02 A6 */ mflr r0
/* 8039AAE8 00397A48 38 80 00 02 */ li r4, 2 /* 8039AAE8 00397A48 38 80 00 02 */ li r4, 2

View File

@ -1,5 +1,12 @@
.include "macros.inc" .include "macros.inc"
.section .bss
.balign 8
.global vs
vs:
.skip 0x950
.section .text, "ax" .section .text, "ax"
.global vsInit .global vsInit

View File

@ -1020,7 +1020,7 @@ lbl_803A3308:
/* 803A330C 003A026C 7F C3 F3 78 */ mr r3, r30 /* 803A330C 003A026C 7F C3 F3 78 */ mr r3, r30
/* 803A3310 003A0270 60 00 00 20 */ ori r0, r0, 0x20 /* 803A3310 003A0270 60 00 00 20 */ ori r0, r0, 0x20
/* 803A3314 003A0274 90 1E 01 18 */ stw r0, 0x118(r30) /* 803A3314 003A0274 90 1E 01 18 */ stw r0, 0x118(r30)
/* 803A3318 003A0278 4B FF 77 C9 */ bl synthkeystateupdate /* 803A3318 003A0278 4B FF 77 C9 */ bl synthKeyStateUpdate
lbl_803A331C: lbl_803A331C:
/* 803A331C 003A027C 80 01 00 24 */ lwz r0, 0x24(r1) /* 803A331C 003A027C 80 01 00 24 */ lwz r0, 0x24(r1)
/* 803A3320 003A0280 83 E1 00 1C */ lwz r31, 0x1c(r1) /* 803A3320 003A0280 83 E1 00 1C */ lwz r31, 0x1c(r1)
@ -4331,7 +4331,7 @@ lbl_803A6150:
/* 803A6154 003A30B4 7F E3 FB 78 */ mr r3, r31 /* 803A6154 003A30B4 7F E3 FB 78 */ mr r3, r31
/* 803A6158 003A30B8 60 00 00 80 */ ori r0, r0, 0x80 /* 803A6158 003A30B8 60 00 00 80 */ ori r0, r0, 0x80
/* 803A615C 003A30BC 90 1F 01 18 */ stw r0, 0x118(r31) /* 803A615C 003A30BC 90 1F 01 18 */ stw r0, 0x118(r31)
/* 803A6160 003A30C0 4B FF 49 81 */ bl synthkeystateupdate /* 803A6160 003A30C0 4B FF 49 81 */ bl synthKeyStateUpdate
/* 803A6164 003A30C4 48 00 09 A0 */ b lbl_803A6B04 /* 803A6164 003A30C4 48 00 09 A0 */ b lbl_803A6B04
.global lbl_803A6168 .global lbl_803A6168
lbl_803A6168: lbl_803A6168:
@ -5633,7 +5633,7 @@ lbl_803A7240:
/* 803A724C 003A41AC 7F 84 E3 78 */ mr r4, r28 /* 803A724C 003A41AC 7F 84 E3 78 */ mr r4, r28
/* 803A7250 003A41B0 54 06 0F FE */ srwi r6, r0, 0x1f /* 803A7250 003A41B0 54 06 0F FE */ srwi r6, r0, 0x1f
/* 803A7254 003A41B4 7E 25 8B 78 */ mr r5, r17 /* 803A7254 003A41B4 7E 25 8B 78 */ mr r5, r17
/* 803A7258 003A41B8 48 00 0B ED */ bl voiceAllocateFind /* 803A7258 003A41B8 48 00 0B ED */ bl voiceAllocate
/* 803A725C 003A41BC 7C 7D 1B 78 */ mr r29, r3 /* 803A725C 003A41BC 7C 7D 1B 78 */ mr r29, r3
/* 803A7260 003A41C0 3C 1D 00 01 */ addis r0, r29, 1 /* 803A7260 003A41C0 3C 1D 00 01 */ addis r0, r29, 1
/* 803A7264 003A41C4 28 00 FF FF */ cmplwi r0, 0xffff /* 803A7264 003A41C4 28 00 FF FF */ cmplwi r0, 0xffff

View File

@ -2,45 +2,68 @@
.section .bss .section .bss
.balign 8 .balign 8
.global vidList .obj vidList, local
vidList: .skip 0x800
.skip 0xF00 .endobj vidList
.global synth_last_fxstarted
synth_last_fxstarted: .obj voicePrioSortVoices
.skip 0x100
.endobj voicePrioSortVoices
.obj voicePrioSortVoicesRoot
.skip 0x100
.endobj voicePrioSortVoicesRoot
.obj voicePrioSortRootList
.skip 0x400
.endobj voicePrioSortRootList
.obj voiceList
.skip 0x100
.endobj voiceList
.obj synth_last_fxstarted, local
.skip 0x40 .skip 0x40
.global synth_last_started .endobj synth_last_fxstarted
synth_last_started:
.obj synth_last_started, local
.skip 0x80 .skip 0x80
.global vs .endobj synth_last_started
vs:
.skip 0x950
.section .sbss .section .sbss
.balign 8 .balign 8
.global vidFree
vidFree: .obj vidFree, local
.skip 0x4 .skip 0x4
.global vidRoot .endobj vidFree
vidRoot:
.obj vidRoot, local
.skip 0x4 .skip 0x4
.global vidCurrentId .endobj vidRoot
vidCurrentId:
.obj vidCurrentId, local
.skip 0x4 .skip 0x4
.global voicePrioSortRootListRoot .endobj vidCurrentId
voicePrioSortRootListRoot:
.obj voicePrioSortRootListRoot
.skip 0x2 .skip 0x2
.global voiceMusicRunning .endobj voicePrioSortRootListRoot
voiceMusicRunning:
.obj voiceMusicRunning
.skip 0x1 .skip 0x1
.global voiceFxRunning .endobj voiceMusicRunning
voiceFxRunning:
.obj voiceFxRunning
.skip 0x1 .skip 0x1
.global voiceListInsert .endobj voiceFxRunning
voiceListInsert:
.obj voiceListInsert
.skip 0x1 .skip 0x1
.global voiceListRoot .endobj voiceListInsert
voiceListRoot:
.skip 0x7 .obj voiceListRoot
.skip 0x1
.endobj voiceListRoot
.section .text, "ax" .section .text, "ax"
@ -637,8 +660,8 @@ lbl_803A7E30:
/* 803A7E3C 003A4D9C 38 21 00 10 */ addi r1, r1, 0x10 /* 803A7E3C 003A4D9C 38 21 00 10 */ addi r1, r1, 0x10
/* 803A7E40 003A4DA0 4E 80 00 20 */ blr /* 803A7E40 003A4DA0 4E 80 00 20 */ blr
.global voiceAllocateFind .global voiceAllocate
voiceAllocateFind: voiceAllocate:
/* 803A7E44 003A4DA4 94 21 FF D0 */ stwu r1, -0x30(r1) /* 803A7E44 003A4DA4 94 21 FF D0 */ stwu r1, -0x30(r1)
/* 803A7E48 003A4DA8 7C 08 02 A6 */ mflr r0 /* 803A7E48 003A4DA8 7C 08 02 A6 */ mflr r0
/* 803A7E4C 003A4DAC 90 01 00 34 */ stw r0, 0x34(r1) /* 803A7E4C 003A4DAC 90 01 00 34 */ stw r0, 0x34(r1)
@ -1282,7 +1305,7 @@ voiceBlock:
/* 803A8728 003A5688 93 C1 00 18 */ stw r30, 0x18(r1) /* 803A8728 003A5688 93 C1 00 18 */ stw r30, 0x18(r1)
/* 803A872C 003A568C 93 A1 00 14 */ stw r29, 0x14(r1) /* 803A872C 003A568C 93 A1 00 14 */ stw r29, 0x14(r1)
/* 803A8730 003A5690 7C 7D 1B 78 */ mr r29, r3 /* 803A8730 003A5690 7C 7D 1B 78 */ mr r29, r3
/* 803A8734 003A5694 4B FF F7 11 */ bl voiceAllocateFind /* 803A8734 003A5694 4B FF F7 11 */ bl voiceAllocate
/* 803A8738 003A5698 7C 7E 1B 78 */ mr r30, r3 /* 803A8738 003A5698 7C 7E 1B 78 */ mr r30, r3
/* 803A873C 003A569C 3C 1E 00 01 */ addis r0, r30, 1 /* 803A873C 003A569C 3C 1E 00 01 */ addis r0, r30, 1
/* 803A8740 003A56A0 28 00 FF FF */ cmplwi r0, 0xffff /* 803A8740 003A56A0 28 00 FF FF */ cmplwi r0, 0xffff

View File

@ -920,19 +920,19 @@ LIBS = [
{ {
"lib": "musyx", "lib": "musyx",
#"mw_version": "1.2.5", #"mw_version": "1.2.5",
#"cflags": "-nodefaults -fp hard -O0 -maxerrors 1 -enum int -str reuse -nosyspath -i include -i libc -use_lmw_stmw on -inline off", #"cflags": "-proc gecko -fp hard -nodefaults -nosyspath -i include -i libc -g -sym on -D_DEBUG=1 -enum int -use_lmw_stmw on",
"mw_version": "1.3.2", "mw_version": "1.3.2",
"cflags": "$cflags_musyx", "cflags": "$cflags_musyx",
"host": False, "host": False,
"objects": [ "objects": [
"musyx/runtime/seq", "musyx/runtime/seq",
"musyx/runtime/synth", ["musyx/runtime/synth", False],
["musyx/runtime/seq_api", True], ["musyx/runtime/seq_api", True],
["musyx/runtime/snd_synthapi", True, {"add_to_all": False}], ["musyx/runtime/snd_synthapi", True, {"add_to_all": False}],
["musyx/runtime/stream", False], ["musyx/runtime/stream", False],
"musyx/runtime/synthdata", "musyx/runtime/synthdata",
"musyx/runtime/synthmacros", "musyx/runtime/synthmacros",
"musyx/runtime/synthvoice", ["musyx/runtime/synthvoice", False],
["musyx/runtime/synth_ac", True], ["musyx/runtime/synth_ac", True],
"musyx/runtime/synth_adsr", "musyx/runtime/synth_adsr",
["musyx/runtime/synth_vsamples", False], ["musyx/runtime/synth_vsamples", False],

View File

@ -2,15 +2,16 @@
#define _MUSYX_ASSERT #define _MUSYX_ASSERT
extern void OSPanic(const char* file, int line, const char* msg, ...); extern void OSPanic(const char* file, int line, const char* msg, ...);
extern void OSReport(const char* msg, ...);
#ifndef ASSERT #ifndef ASSERT
#ifdef _DEBUG #ifdef _DEBUG
#define ASSERT(cond) \ #define ASSERT(cond) \
do { \ do { \
if (!cond) { \ if (!(cond)) { \
OSPanic(__FILE__, __LINE__, "Failed assertion " #cond); \ OSPanic(__FILE__, __LINE__, "Failed assertion " #cond); \
} \ } \
} while (0) } while(0)
#else #else
#define ASSERT(cond) #define ASSERT(cond)
#endif #endif
@ -18,21 +19,21 @@ extern void OSPanic(const char* file, int line, const char* msg, ...);
#ifndef ASSERT_MSG #ifndef ASSERT_MSG
#ifdef _DEBUG #ifdef _DEBUG
#define ASSERT_MSG(cond, msg) \ #define ASSERT_MSG(cond, msg) \
do { \ do { \
if (!cond) { \ if (!(cond)) { \
OSPanic(__FILE__, __LINE__, msg); \ OSPanic(__FILE__, __LINE__, msg); \
} \ } \
} while (0) } while(0)
#else #else
#define ASSERT_MSG(cond, msg) #define ASSERT_MSG(cond, msg)
#endif #endif
#endif #endif
#ifndef MUSY_DEBUG #ifndef MUSY_DEBUG
#if _DEBUG #ifdef _DEBUG
#define MUSY_DEBUG OSReport #define MUSY_DEBUG OSReport
#else #else
#define MUSY_DEBUG #define MUSY_DEBUG
#endif #endif
#endif #endif

View File

@ -15,6 +15,24 @@ typedef struct SND_STUDIO_INPUT {
unsigned char srcStudio; // offset 0x3, size 0x1 unsigned char srcStudio; // offset 0x3, size 0x1
} SND_STUDIO_INPUT; } SND_STUDIO_INPUT;
typedef struct SYNTH_VOICELIST {
// total size: 0x4
u8 prev; // offset 0x0, size 0x1
u8 next; // offset 0x1, size 0x1
u16 user; // offset 0x2, size 0x2
} SYNTH_VOICELIST;
extern SYNTH_VOICELIST voicePrioSortVoices[64];
extern u8 voicePrioSortVoicesRoot[256];
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
} SYNTH_ROOTLIST;
extern SYNTH_ROOTLIST voicePrioSortRootList[256];
typedef struct synthInfo { typedef struct synthInfo {
u32 mixFrq; u32 mixFrq;
u32 numSamples; u32 numSamples;
@ -287,6 +305,19 @@ typedef struct SYNTH_QUEUE {
u8 jobTabIndex; u8 jobTabIndex;
} SYNTH_QUEUE; } SYNTH_QUEUE;
typedef enum {
SYNTH_JOBTYPE_LOW = 0,
SYNTH_JOBTYPE_ZERO = 1,
SYNTH_JOBTYPE_EVENT = 2,
} SYNTH_JOBTYPE;
typedef struct {
// total size: 0xC
SYNTH_QUEUE* lowPrecision; // offset 0x0, size 0x4
SYNTH_QUEUE* event; // offset 0x4, size 0x4
SYNTH_QUEUE* zeroOffset; // offset 0x8, size 0x4
} SYNTH_JOBTAB;
typedef struct SYNTH_LFO { typedef struct SYNTH_LFO {
u32 time; u32 time;
u32 period; u32 period;
@ -294,6 +325,23 @@ typedef struct SYNTH_LFO {
s16 lastValue; s16 lastValue;
} SYNTH_LFO; } SYNTH_LFO;
typedef struct SYNTHMasterFader {
// total size: 0x30
float volume; // offset 0x0, size 0x4
float target; // offset 0x4, size 0x4
float start; // offset 0x8, size 0x4
float time; // offset 0xC, size 0x4
float deltaTime; // offset 0x10, size 0x4
float pauseVol; // offset 0x14, size 0x4
float pauseTarget; // offset 0x18, size 0x4
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
} SYNTHMasterFader;
typedef struct CTRL_SOURCE { typedef struct CTRL_SOURCE {
u8 midiCtrl; u8 midiCtrl;
u8 combine; u8 combine;
@ -377,7 +425,7 @@ typedef struct SYNTH_VOICE {
u32 parent; u32 parent;
u32 id; u32 id;
VID_LIST* vidList; VID_LIST* vidList;
VID_LIST* vidListMaster; VID_LIST* vidMasterList;
u16 allocId; u16 allocId;
u16 macroId; u16 macroId;
u8 keyGroup; u8 keyGroup;
@ -473,8 +521,36 @@ typedef struct SYNTH_VOICE {
long mesgQueue[4]; // offset 0x3F0, size 0x10 long mesgQueue[4]; // offset 0x3F0, size 0x10
u16 curOutputVolume; // offset 0x400, size 0x2 u16 curOutputVolume; // offset 0x400, size 0x2
} SYNTH_VOICE; } SYNTH_VOICE;
typedef struct synthITDInfo {
// total size: 0x2
unsigned char music; // offset 0x0, size 0x1
unsigned char sfx; // offset 0x1, size 0x1
} synthITDInfo;
#pragma pop #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
} 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
} KEYMAP;
typedef struct SAL_VOLINFO { typedef struct SAL_VOLINFO {
// total size: 0x24 // total size: 0x24
float volL; // offset 0x0, size 0x4 float volL; // offset 0x0, size 0x4
@ -584,8 +660,27 @@ extern SYNTH_VOICE* synthVoice;
extern DSPvoice* dspVoice; extern DSPvoice* dspVoice;
typedef s32 (*SND_COMPARE)(u16*, u8*); typedef s32 (*SND_COMPARE)(u16*, u8*);
void dataInit(u32, s32); /* extern */ typedef struct FX_TAB {
void dataInitStack(); /* extern */ // 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
} FX_TAB;
typedef struct FX_DATA {
// total size: 0xE
unsigned short num; // offset 0x0, size 0x2
unsigned short reserverd; // offset 0x2, size 0x2
struct FX_TAB fx[1]; // offset 0x4, size 0xA
} FX_DATA;
void dataInit(u32, s32); /* extern */
void dataInitStack(); /* extern */
FX_TAB* dataGetFX(u16 fid);
s32 hwInit(u32* frq, u16 numVoices, u16 numStudios, u32 flags); /* extern */ s32 hwInit(u32* frq, u16 numVoices, u16 numStudios, u32 flags); /* extern */
void hwEnableIrq(); void hwEnableIrq();
void hwDisableIrq(); void hwDisableIrq();
@ -598,20 +693,21 @@ void hwExit();
void dataExit(); void dataExit();
void s3dExit(); void s3dExit();
void synthExit(); void synthExit();
u32 synthGetTicksPerSecond(u32 seconds); u32 synthGetTicksPerSecond(SYNTH_VOICE* svoice);
u16 sndRand(void); u16 sndRand(void);
s16 sndSin(u32 __x); s16 sndSin(u16 angle);
u8* sndBSearch(u16* key, u8* subTab, s32 mainTab, s32 len, SND_COMPARE cmp); u8* sndBSearch(u16* key, u8* subTab, s32 mainTab, s32 len, SND_COMPARE cmp);
void sndConvertMs(u32* time); void sndConvertMs(u32* time);
void sndConvertTicks(u32* out, u32 seconds); void sndConvertTicks(u32* out, SYNTH_VOICE* svoice);
u32 sndConvert2Ms(u32 time); u32 sndConvert2Ms(u32 time);
void hwActivateStudio(unsigned char studio, unsigned long isMaster, SND_STUDIO_TYPE type); void hwActivateStudio(unsigned char studio, unsigned long isMaster, SND_STUDIO_TYPE type);
void hwDeactivateStudio(u8); void hwDeactivateStudio(u8);
u32 hwIsActive(u32); u32 hwIsActive(u32);
u32 sndGetPitch(u8 key, u32 sInfo);
extern SND_HOOKS salHooks; extern SND_HOOKS salHooks;
extern u8 sndActive; extern u8 sndActive;
extern s8 synthIdleWaitActive; extern u8 synthIdleWaitActive;
extern SynthInfo synthInfo; extern SynthInfo synthInfo;
typedef s32 (*SND_MESSAGE_CALLBACK)(u32, u32); typedef s32 (*SND_MESSAGE_CALLBACK)(u32, u32);
typedef void (*SND_SOME_CALLBACK)(); typedef void (*SND_SOME_CALLBACK)();
@ -662,7 +758,7 @@ typedef struct SND_STREAM_INFO {
} SND_STREAM_INFO; } SND_STREAM_INFO;
void streamOutputModeChanged(); void streamOutputModeChanged();
unsigned short inpGetMidiCtrl(unsigned char ctrl, unsigned char channel, unsigned char set);
/* TODO: Figure out what `unk` is */ /* TODO: Figure out what `unk` is */
void hwSetSRCType(u32 v, u8 salSRCType); void hwSetSRCType(u32 v, u8 salSRCType);
void hwSetITDMode(u32 v, u8 mode); void hwSetITDMode(u32 v, u8 mode);
@ -687,6 +783,8 @@ void aramUploadData(void* mram, unsigned long aram, unsigned long len, unsigned
void aramFreeStreamBuffer(u8 id); void aramFreeStreamBuffer(u8 id);
void* aramStoreData(void* src, unsigned long len); void* aramStoreData(void* src, unsigned long len);
void aramRemoveData(void* aram, unsigned long len); void aramRemoveData(void* aram, unsigned long len);
void macMakeInactive(SYNTH_VOICE* svoice, MAC_STATE);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -1,17 +1,11 @@
#include "musyx/assert.h" #include "musyx/assert.h"
#include "musyx/musyx_priv.h" #include "musyx/musyx_priv.h"
u16 dspSRCCycles[3][3] = { #ifdef _DEBUG
{2990, 2990, 1115}, static u32 dbgActiveVoicesMax = 0;
{3300, 3300, 1115}, #endif
{3700, 3700, 1115},
};
static const u16 dspMixerCycles[32] = {
1470, 2940, 2940, 4410, 2230, 4460, 4460, 6690, 2470, 4940, 4940, 7410, 3735, 7470, 7470, 11205,
2940, 3386, 2940, 3386, 2940, 3386, 2940, 3386, 4940, 5687, 4940, 5687, 4940, 5687, 4940, 5687,
};
extern u8 salAuxFrame;
DSPstudioinfo dspStudio[8]; DSPstudioinfo dspStudio[8];
static u32 dspARAMZeroBuffer = 0; static u32 dspARAMZeroBuffer = 0;
u16* dspCmdLastLoad = NULL; u16* dspCmdLastLoad = NULL;
@ -36,26 +30,23 @@ u32 salInitDspCtrl(u8 numVoices, u8 numStudios, u32 defaultStudioDPL2) {
salNumVoices = numVoices; salNumVoices = numVoices;
salMaxStudioNum = numStudios; salMaxStudioNum = numStudios;
#line 66
ASSERT(salMaxStudioNum <= SAL_MAX_STUDIONUM); ASSERT(salMaxStudioNum <= SAL_MAX_STUDIONUM);
dspARAMZeroBuffer = aramGetZeroBuffer(); dspARAMZeroBuffer = aramGetZeroBuffer();
dspCmdList = salMalloc(1024 * sizeof(u16)); if ((dspCmdList = salMalloc(1024 * sizeof(u16))) != NULL) {
if (dspCmdList != NULL) { MUSY_DEBUG("Allocated dspCmdList.\n\n");
// OSReport("Allocated dspCmdList.\n\n"); if ((dspSurround = salMalloc(160 * sizeof(long))) != NULL) {
dspSurround = salMalloc(160 * sizeof(long)); MUSY_DEBUG("Allocated surround buffer.\n\n");
if (dspSurround != NULL) {
// OSReport("Allocated surround buffer.\n\n");
memset(dspSurround, 0, 160 * sizeof(long)); memset(dspSurround, 0, 160 * sizeof(long));
DCFlushRange(dspSurround, 160 * sizeof(long)); DCFlushRange(dspSurround, 160 * sizeof(long));
dspVoice = salMalloc(salNumVoices * sizeof(DSPvoice)); if ((dspVoice = salMalloc(salNumVoices * sizeof(DSPvoice))) != NULL) {
if (dspVoice != NULL) { MUSY_DEBUG("Allocated HW voice array.\n\n");
// OSReport("Allocated HW voice array.\n\n"); if ((dspITDBuffer = salMalloc(salNumVoices * 64)) != NULL) {
dspITDBuffer = salMalloc(salNumVoices * 64); MUSY_DEBUG("Allocated ITD buffers for voice array.\n\n");
if (dspITDBuffer != NULL) {
// OSReport("Allocated ITD buffers for voice array.\n\n");
DCInvalidateRange(dspITDBuffer, salNumVoices * 64); DCInvalidateRange(dspITDBuffer, salNumVoices * 64);
itdPtr = (u32)dspITDBuffer; itdPtr = (u32)dspITDBuffer;
for (i = 0; i < salNumVoices; ++i) { for (i = 0; i < salNumVoices; ++i) {
// OSReport("Initializing voice %d...\n", i); MUSY_DEBUG("Initializing voice %d...\n", i);
dspVoice[i].state = 0; dspVoice[i].state = 0;
dspVoice[i].postBreak = 0; dspVoice[i].postBreak = 0;
dspVoice[i].startupBreak = 0; dspVoice[i].startupBreak = 0;
@ -82,20 +73,16 @@ u32 salInitDspCtrl(u8 numVoices, u8 numStudios, u32 defaultStudioDPL2) {
} }
} }
// OSReport("All voices initialized.\n\n"); MUSY_DEBUG("All voices initialized.\n\n");
for (i = 0; i < salMaxStudioNum; ++i) { for (i = 0; i < salMaxStudioNum; ++i) {
// OSReport("Initializing studio %d...\n", i); MUSY_DEBUG("Initializing studio %d...\n", i);
dspStudio[i].state = 0; dspStudio[i].state = 0;
itdPtr = (u32)salMalloc(sizeof(_SPB)); if ((dspStudio[i].spb = (_SPB*)salMalloc(sizeof(_SPB))) == NULL) {
dspStudio[i].spb = (void*)itdPtr;
if ((void*)itdPtr == NULL) {
return FALSE; return FALSE;
} }
itdPtr = (u32)salMalloc(0x3c00); if ((dspStudio[i].main[0] = (void*)salMalloc(0x3c00)) == NULL) {
dspStudio[i].main[0] = (void*)itdPtr;
if ((void*)itdPtr == NULL) {
return FALSE; return FALSE;
} }
@ -109,22 +96,19 @@ u32 salInitDspCtrl(u8 numVoices, u8 numStudios, u32 defaultStudioDPL2) {
dspStudio[i].auxB[1] = dspStudio[i].auxB[0] + 0x1e0; dspStudio[i].auxB[1] = dspStudio[i].auxB[0] + 0x1e0;
dspStudio[i].auxB[2] = dspStudio[i].auxB[1] + 0x1e0; dspStudio[i].auxB[2] = dspStudio[i].auxB[1] + 0x1e0;
memset(dspStudio[i].spb, 0, sizeof(_SPB)); memset(dspStudio[i].spb, 0, sizeof(_SPB));
dspStudio[i].hostDPopSum.s = 0; dspStudio[i].hostDPopSum.l = dspStudio[i].hostDPopSum.r = dspStudio[i].hostDPopSum.s =
dspStudio[i].hostDPopSum.r = 0; 0;
dspStudio[i].hostDPopSum.l = 0; dspStudio[i].hostDPopSum.lA = dspStudio[i].hostDPopSum.rA =
dspStudio[i].hostDPopSum.sA = 0; dspStudio[i].hostDPopSum.sA = 0;
dspStudio[i].hostDPopSum.rA = 0; dspStudio[i].hostDPopSum.lB = dspStudio[i].hostDPopSum.rB =
dspStudio[i].hostDPopSum.lA = 0; dspStudio[i].hostDPopSum.sB = 0;
dspStudio[i].hostDPopSum.sB = 0;
dspStudio[i].hostDPopSum.rB = 0;
dspStudio[i].hostDPopSum.lB = 0;
DCFlushRangeNoSync(dspStudio[i].spb, sizeof(_SPB)); DCFlushRangeNoSync(dspStudio[i].spb, sizeof(_SPB));
} }
// OSReport("All studios are initialized.\n\n"); MUSY_DEBUG("All studios are initialized.\n\n");
salActivateStudio(0, 1, defaultStudioDPL2 != FALSE); salActivateStudio(
// OSReport("Default studio is active.\n\n"); 0, 1, defaultStudioDPL2 != FALSE ? SND_STUDIO_TYPE_RESERVED0 : SND_STUDIO_TYPE_STD);
dspHrtfHistoryBuffer = salMalloc(0x100); MUSY_DEBUG("Default studio is active.\n\n");
if (dspHrtfHistoryBuffer == NULL) { if ((dspHrtfHistoryBuffer = salMalloc(0x100)) == NULL) {
return FALSE; return FALSE;
} }
@ -168,15 +152,13 @@ void salActivateStudio(u8 studio, u32 isMaster, SND_STUDIO_TYPE type) {
memset(dspStudio[studio].main[0], 0, 0x3c00); memset(dspStudio[studio].main[0], 0, 0x3c00);
DCFlushRangeNoSync(dspStudio[studio].main[0], 0x3c00); DCFlushRangeNoSync(dspStudio[studio].main[0], 0x3c00);
memset(dspStudio[studio].spb, 0, sizeof(_SPB)); memset(dspStudio[studio].spb, 0, sizeof(_SPB));
dspStudio[studio].hostDPopSum.s = 0; dspStudio[studio].hostDPopSum.l = dspStudio[studio].hostDPopSum.r =
dspStudio[studio].hostDPopSum.r = 0; dspStudio[studio].hostDPopSum.s = 0;
dspStudio[studio].hostDPopSum.l = 0; dspStudio[studio].hostDPopSum.lA = dspStudio[studio].hostDPopSum.rA =
dspStudio[studio].hostDPopSum.sA = 0; dspStudio[studio].hostDPopSum.sA = 0;
dspStudio[studio].hostDPopSum.rA = 0; dspStudio[studio].hostDPopSum.lB = dspStudio[studio].hostDPopSum.rB =
dspStudio[studio].hostDPopSum.lA = 0; dspStudio[studio].hostDPopSum.sB = 0;
dspStudio[studio].hostDPopSum.sB = 0;
dspStudio[studio].hostDPopSum.rB = 0;
dspStudio[studio].hostDPopSum.lB = 0;
DCFlushRangeNoSync(dspStudio[studio].spb, sizeof(_SPB)); DCFlushRangeNoSync(dspStudio[studio].spb, sizeof(_SPB));
memset(dspStudio[studio].auxA[0], 0, 0x780); memset(dspStudio[studio].auxA[0], 0, 0x780);
DCFlushRangeNoSync(dspStudio[studio].auxA[0], 0x780); DCFlushRangeNoSync(dspStudio[studio].auxA[0], 0x780);
@ -188,10 +170,20 @@ void salActivateStudio(u8 studio, u32 isMaster, SND_STUDIO_TYPE type) {
dspStudio[studio].isMaster = isMaster; dspStudio[studio].isMaster = isMaster;
dspStudio[studio].numInputs = 0; dspStudio[studio].numInputs = 0;
dspStudio[studio].type = type; dspStudio[studio].type = type;
dspStudio[studio].auxBHandler = NULL; dspStudio[studio].auxAHandler = dspStudio[studio].auxBHandler = NULL;
dspStudio[studio].auxAHandler = NULL;
} }
u16 dspSRCCycles[3][3] = {
{2990, 2990, 1115},
{3300, 3300, 1115},
{3700, 3700, 1115},
};
static const u16 dspMixerCycles[32] = {
1470, 2940, 2940, 4410, 2230, 4460, 4460, 6690, 2470, 4940, 4940, 7410, 3735, 7470, 7470, 11205,
2940, 3386, 2940, 3386, 2940, 3386, 2940, 3386, 4940, 5687, 4940, 5687, 4940, 5687, 4940, 5687,
};
void salDeactivateStudio(u8 studio) { dspStudio[studio].state = 0; } void salDeactivateStudio(u8 studio) { dspStudio[studio].state = 0; }
u32 salCheckVolErrorAndResetDelta(u16* dsp_vol, u16* dsp_delta, u16* last_vol, u16 targetVol, u32 salCheckVolErrorAndResetDelta(u16* dsp_vol, u16* dsp_delta, u16* last_vol, u16 targetVol,
@ -201,9 +193,9 @@ u32 salCheckVolErrorAndResetDelta(u16* dsp_vol, u16* dsp_delta, u16* last_vol, u
if (targetVol != *last_vol) { if (targetVol != *last_vol) {
d = (s16)targetVol - (s16)*last_vol; d = (s16)targetVol - (s16)*last_vol;
if (d >= 32 && d < 160) { if ((s16)d >= 32 && (s16)d < 160) {
d = d >> 5; d = (s16)d >> 5;
if (d < 5) { if ((s16)d < 5) {
resetFlags[d] |= resetMask; resetFlags[d] |= resetMask;
} }
@ -212,19 +204,18 @@ u32 salCheckVolErrorAndResetDelta(u16* dsp_vol, u16* dsp_delta, u16* last_vol, u
return 1; return 1;
} }
if (-32 >= d && -160 < d) { if (-32 >= (s16)d && -160 < (s16)d) {
d = -d >> 5; d = -(s16)d >> 5;
if (d < 5) { if (d < 5) {
resetFlags[d] |= resetMask; resetFlags[d] |= resetMask;
} }
*dsp_delta = 0xFFFF; *dsp_delta = 0xFFFF;
*last_vol -= d * 32; *last_vol -= (s16)d * 32;
return 1; return 1;
} }
if (targetVol == 0 && d > -32) { if (targetVol == 0 && (s16)d > -32) {
*last_vol = 0; *dsp_vol = *last_vol = 0;
*dsp_vol = 0;
} }
} }
@ -351,16 +342,13 @@ u32 salSynthSendMessage(DSPvoice* dsp_vptr, u32 mesg) {
} }
void salActivateVoice(DSPvoice* dsp_vptr, u8 studio) { void salActivateVoice(DSPvoice* dsp_vptr, u8 studio) {
DSPvoice* tmp;
if (dsp_vptr->state != 0) { if (dsp_vptr->state != 0) {
salDeactivateVoice(dsp_vptr); salDeactivateVoice(dsp_vptr);
dsp_vptr->changed[0] |= 0x20; dsp_vptr->changed[0] |= 0x20;
} }
dsp_vptr->postBreak = 0; dsp_vptr->postBreak = 0;
tmp = dspStudio[studio].voiceRoot; if ((dsp_vptr->next = dspStudio[studio].voiceRoot) != NULL) {
dsp_vptr->next = tmp;
if (tmp != NULL) {
dsp_vptr->next->prev = dsp_vptr; dsp_vptr->next->prev = dsp_vptr;
} }
@ -390,7 +378,6 @@ void salDeactivateVoice(DSPvoice* dsp_vptr) {
} }
void salReconnectVoice(DSPvoice* dsp_vptr, u8 studio) { void salReconnectVoice(DSPvoice* dsp_vptr, u8 studio) {
DSPvoice* tmp;
if (dsp_vptr->state != 0) { if (dsp_vptr->state != 0) {
if (dsp_vptr->prev != NULL) { if (dsp_vptr->prev != NULL) {
dsp_vptr->prev->next = dsp_vptr->next; dsp_vptr->prev->next = dsp_vptr->next;
@ -402,9 +389,7 @@ void salReconnectVoice(DSPvoice* dsp_vptr, u8 studio) {
dsp_vptr->next->prev = dsp_vptr->prev; dsp_vptr->next->prev = dsp_vptr->prev;
} }
tmp = dspStudio[studio].voiceRoot; if ((dsp_vptr->next = dspStudio[studio].voiceRoot) != NULL) {
dsp_vptr->next = tmp;
if (tmp != NULL) {
dsp_vptr->next->prev = dsp_vptr; dsp_vptr->next->prev = dsp_vptr;
} }
@ -437,7 +422,7 @@ unsigned long salRemoveStudioInput(DSPstudioinfo* stp, SND_STUDIO_INPUT* desc) {
long i; // r31 long i; // r31
i = 0; i = 0;
while(i <= stp->numInputs) { while (i < stp->numInputs) {
if (stp->in[i].desc == desc) { if (stp->in[i].desc == desc) {
break; break;
} }
@ -452,3 +437,35 @@ unsigned long salRemoveStudioInput(DSPstudioinfo* stp, SND_STUDIO_INPUT* desc) {
--stp->numInputs; --stp->numInputs;
return 1; return 1;
} }
void salHandleAuxProcessing() {
u8 st; // r29
long* work; // r30
DSPstudioinfo* sp; // r31
SND_AUX_INFO info; // r1+0x8
sp = &dspStudio[0];
for (st = 0; st < salMaxStudioNum; ++st, ++sp) {
if (sp->state != 1) {
continue;
}
if (sp->auxAHandler != NULL) {
work = sp->auxA[(salAuxFrame + 2) % 3];
info.data.bufferUpdate.left = work;
info.data.bufferUpdate.right = work + 0xa0;
info.data.bufferUpdate.surround = work + 0x140;
sp->auxAHandler(0, &info, sp->auxAUser);
DCFlushRangeNoSync(work, 0x780);
}
if (sp->type == 0 && sp->auxBHandler != 0) {
work = sp->auxB[(salAuxFrame + 2) % 3];
info.data.bufferUpdate.left = work;
info.data.bufferUpdate.right = work + 0xa0;
info.data.bufferUpdate.surround = work + 0x140;
sp->auxBHandler(0, &info, sp->auxBUser);
DCFlushRangeNoSync(work, 0x780);
}
}
}

View File

@ -71,7 +71,7 @@ s16 sndSintab[1024] = {
4094, 4094, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4094, 4094, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095, 4095,
}; };
#define SINTAB_ELEMENT_COUNT (sizeof(sndSintab) / sizeof(short) - 1) #define SINTAB_ELEMENT_COUNT (sizeof(sndSintab) / sizeof(u16) - 1)
u32 last_rnd = 1; u32 last_rnd = 1;
@ -80,18 +80,18 @@ u16 sndRand(void) {
return last_rnd >> 6; return last_rnd >> 6;
} }
s16 sndSin(u32 __x) { s16 sndSin(u16 angle) {
const u16 x = __x & 0xFFF; angle &= 0xFFF;
if (x < 1024) { if (angle < 1024) {
return (int)sndSintab[x]; return (s16)sndSintab[angle];
} }
if (x < 2048) { if (angle < 2048) {
return (int)sndSintab[SINTAB_ELEMENT_COUNT - (x & SINTAB_ELEMENT_COUNT)]; return (s16)sndSintab[SINTAB_ELEMENT_COUNT - (angle & SINTAB_ELEMENT_COUNT)];
} }
if (x < 3072) { if (angle < 3072) {
return (int)-sndSintab[x & SINTAB_ELEMENT_COUNT]; return (s16)-sndSintab[angle & SINTAB_ELEMENT_COUNT];
} }
return -sndSintab[SINTAB_ELEMENT_COUNT - (x & SINTAB_ELEMENT_COUNT)]; return -sndSintab[SINTAB_ELEMENT_COUNT - (angle & SINTAB_ELEMENT_COUNT)];
} }
u8* sndBSearch(u16* key, u8* subTab, s32 mainTab, s32 len, SND_COMPARE cmp) { u8* sndBSearch(u16* key, u8* subTab, s32 mainTab, s32 len, SND_COMPARE cmp) {
@ -124,8 +124,8 @@ u8* sndBSearch(u16* key, u8* subTab, s32 mainTab, s32 len, SND_COMPARE cmp) {
void sndConvertMs(u32* time) { *time = *time * 256; } void sndConvertMs(u32* time) { *time = *time * 256; }
void sndConvertTicks(u32* out, u32 seconds) { void sndConvertTicks(u32* out, SYNTH_VOICE* svoice) {
*out = (((*out << 16) / synthGetTicksPerSecond(seconds)) * 1000) / 32; *out = (((*out << 16) / synthGetTicksPerSecond(svoice)) * 1000) / 32;
} }
u32 sndConvert2Ms(u32 time) { return time / 256; } u32 sndConvert2Ms(u32 time) { return time / 256; }

297
src/musyx/runtime/synth.c Normal file
View File

@ -0,0 +1,297 @@
#include "musyx/assert.h"
#include "musyx/musyx_priv.h"
static u32 synthTicksPerSecond[9][16];
static SYNTH_JOBTAB synthJobTable[32];
CTRL_DEST inpAuxA[8][4];
CTRL_DEST inpAuxB[8][4];
long synthGlobalVariable[16];
synthITDInfo synthITDDefault[8];
void* synthAuxBUser[8];
SND_AUX_CALLBACK synthAuxBCallback[8];
void* synthAuxAUser[8];
SND_AUX_CALLBACK synthAuxACallback[8];
u8 synthTrackVolume[64];
SYNTHMasterFader synthMasterFader[32];
SynthInfo synthInfo;
u8 sndActive = 0;
static u8 synthJobTableIndex = 0;
u64 synthRealTime;
u8 synthIdleWaitActive;
SND_MESSAGE_CALLBACK synthMessageCallback;
SYNTH_VOICE* synthVoice;
u32 synthFlags;
u32 synthMasterFaderActiveFlags;
u32 synthMasterFaderPauseActiveFlags;
u8 synthAuxAMIDI[8];
u8 synthAuxAMIDISet[8];
u8 synthAuxBMIDI[8];
u8 synthAuxBMIDISet[8];
u8 synthTrackVolume[64]; // size: 0x40
void synthSetBpm(u32 bpm, u8 set, u8 section) {
if (set == 0xFF) {
set = 8;
}
synthTicksPerSecond[set][section] = ((bpm << 3) * 1536) / 240;
}
u32 synthGetTicksPerSecond(SYNTH_VOICE* svoice) {
return synthTicksPerSecond[svoice->midiSet == 0xFF ? 8 : svoice->midiSet][svoice->section];
}
static u32 apply_portamento(SYNTH_VOICE* svoice, u32 ccents, u32 deltaTime) {
u32 old_portCurPitch; // r31
if ((svoice->cFlags & 0x400) != 0 && (int)((svoice->portDuration - svoice->portTime) >> 8) > 0) {
old_portCurPitch = svoice->portCurPitch;
svoice->portCurPitch += (int)deltaTime * ((int)(ccents - svoice->portCurPitch) >> 8) /
(int)((svoice->portDuration - svoice->portTime) >> 8);
if ((old_portCurPitch < ccents && svoice->portCurPitch < ccents) ||
(old_portCurPitch > ccents && (svoice->portCurPitch > ccents))) {
ccents = svoice->portCurPitch;
svoice->portTime += deltaTime;
} else {
svoice->portTime = svoice->portDuration;
}
}
return ccents;
}
void synthInitPortamento(SYNTH_VOICE* svoice) {
if (svoice->cFlags & 0x20000) {
return;
}
if (svoice->portType == 1) {
if (!(svoice->cFlags & 0x1000)) {
svoice->portTime = 0;
} else {
svoice->portTime = svoice->portDuration;
}
} else {
svoice->portTime = svoice->portDuration;
}
svoice->portCurPitch = svoice->lastNote << 16;
}
static u32 do_voice_portamento(u8 key, u8 midi, u8 midiSet, u32 isMaster, u32* rejected) {
u32 i; // r30
u32 vid; // r29
u32 id; // r27
SYNTH_VOICE* sv; // r31
SYNTH_VOICE* last_sv; // r28
u32 legatoVoiceIsStarting; // r26
}
static u32 check_portamento(u8 key, u8 midi, u8 midiSet, u32 newVID, u32* vid) {
u32 rejected; // r1+0x14
if (inpGetMidiCtrl(65, midi, midiSet) > 8064) {
*vid = do_voice_portamento(key & 0x7f, midi, midiSet, newVID, &rejected);
return !rejected;
}
*vid = 0xFFFFFFFF;
return 1;
}
static u32 StartLayer(u16 layerID, s16 prio, u8 maxVoices, u16 allocId, u8 key, u8 vol, u8 panning,
u8 midi, u8 midiSet, u8 section, u16 step, u16 trackid, u32 vidFlag,
u8 vGroup, u8 studio, u32 itd) {
u16 n; // r1+0x38
u32 vid; // r26
u32 new_id; // r1+0x34
u32 id; // r27
LAYER* l; // r31
long p; // r30
long k; // r29
u8 v; // r25
u8 mKey; // r24
}
static u32 StartKeymap(u16 keymapID, s16 prio, u8 maxVoices, u16 allocId, u8 key, u8 vol,
u8 panning, u8 midi, u8 midiSet, u8 section, u16 step, u16 trackid,
u32 vidFlag, u8 vGroup, u8 studio, u32 itd) {
u8 o; // r30
struct KEYMAP* keymap; // r31
long p; // r26
long k; // r29
u32 vid; // r1+0x34
}
#pragma dont_inline on
u32 synthStartSound(u16 id, u8 prio, u8 max, u8 key, u8 vol, u8 panning, u8 midi, u8 midiSet,
u8 section, u16 step, u16 trackid, u8 vGroup, s16 prioOffset, u8 studio,
u32 itd) {
u32 vid; // r1+0x34
}
#pragma dont_inline reset
static u32 convert_cents(SYNTH_VOICE* svoice, u32 ccents) {
unsigned long curDetune; // r30
unsigned long cpitch; // r31
}
static void UpdateTimeMIDICtrl(SYNTH_VOICE* sv) {
if (!sv->timeUsedByInput) {
return;
}
sv->timeUsedByInput = 0;
sv->midiDirtyFlags = 0x1fff;
}
static void LowPrecisionHandler(unsigned long i) {
unsigned long j; // r30
long pbend; // r29
unsigned long ccents; // r28
unsigned long cpitch; // r26
unsigned short Modulation; // r24
unsigned short portamento; // r25
unsigned long lowDeltaTime; // r27
struct SYNTH_VOICE* sv; // r31
unsigned long cntDelta; // r20
unsigned long addFactor; // r19
unsigned short adsr_start; // r1+0xE
unsigned short adsr_delta; // r1+0xC
long vrange; // r23
long voff; // r22
}
static void ZeroOffsetHandler(unsigned long i) {
struct SYNTH_VOICE* sv; // r31
unsigned long lowDeltaTime; // r26
unsigned short Modulation; // r25
float vol; // r62
float auxa; // r57
float auxb; // r56
float f; // r59
float voiceVol; // r60
unsigned long volUpdate; // r30
float lfo; // r55
float scale; // r63
float mscale; // r54
long pan; // r28
float preVol; // r58
float postVol; // r61
}
static void EventHandler(unsigned long i) {
SYNTH_VOICE* sv; // r31
}
static void synthInitJobQueue() {
u8 i; // r31
for (i = 0; i < 32; ++i) {
synthJobTable[i].lowPrecision = NULL;
synthJobTable[i].event = NULL;
synthJobTable[i].zeroOffset = NULL;
}
synthJobTableIndex = 0;
}
#pragma dont_inline on
void synthAddJob(SYNTH_VOICE* svoice, SYNTH_JOBTYPE jobType, unsigned long deltaTime) {
SYNTH_QUEUE* newJq; // r31
SYNTH_QUEUE** root; // r30
u8 jobTabIndex; // r29
SYNTH_JOBTAB* jobTab; // r28
}
#pragma dont_inline reset
void synthStartSynthJobHandling(SYNTH_VOICE* svoice) {
svoice->lastLowCallTime = synthRealTime;
svoice->lastZeroCallTime = synthRealTime;
synthAddJob(svoice, SYNTH_JOBTYPE_LOW, 0);
synthAddJob(svoice, SYNTH_JOBTYPE_ZERO, 0);
}
void synthForceLowPrecisionUpdate(SYNTH_VOICE* svoice) {
synthAddJob(svoice, SYNTH_JOBTYPE_LOW, 0);
synthAddJob(svoice, SYNTH_JOBTYPE_ZERO, 0);
}
void synthKeyStateUpdate(SYNTH_VOICE* svoice) { synthAddJob(svoice, SYNTH_JOBTYPE_EVENT, 0); }
void HandleJobQueue(SYNTH_QUEUE** queueRoot, void (*handler)(unsigned long)) {
SYNTH_QUEUE* jq; // r31
SYNTH_QUEUE* nextJq; // r30
jq = *queueRoot;
while (jq != NULL) {
nextJq = jq->next;
jq->jobTabIndex = 0xff;
if (!synthVoice[jq->voice].block) {
handler(jq->voice);
}
jq = nextJq;
}
*queueRoot = NULL;
}
void HandleVoices() {
SYNTH_JOBTAB* jTab = &synthJobTable[synthJobTableIndex]; // r31
HandleJobQueue(&jTab->lowPrecision, LowPrecisionHandler);
HandleJobQueue(&jTab->event, EventHandler);
HandleJobQueue(&jTab->zeroOffset, ZeroOffsetHandler);
synthJobTableIndex = synthJobTableIndex + 1 & 0x1f;
}
void HandleFaderTermination(SYNTHMasterFader* smf) {
switch (smf->seqMode) {
case 1:
seqStop(smf->seqId);
break;
case 2:
seqPause(smf->seqId);
break;
case 3:
seqMute(smf->seqId, 0, 0);
break;
}
}
void synthHandle(unsigned long deltaTime) {
unsigned long i; // r29
unsigned long s; // r30
SYNTHMasterFader* smf; // r31
unsigned long testFlag; // r27
SND_AUX_INFO info; // r1+0x18
}
unsigned char synthFXGetMaxVoices(u16 fid) {
FX_TAB* fx;
if ((fx = dataGetFX(fid)) != NULL) {
return fx->maxVoices;
}
return 0;
}
u32 synthFXStart(u16 fid, u8 vol, u8 pan, u8 studio, u32 itd) {
FX_TAB* fx;
u32 v;
v = 0xFFFFFFFF;
if ((fx = dataGetFX(fid)) != NULL) {
if (vol == 0xFF) {
vol = fx->volume;
}
if (pan == 0xFF) {
pan = fx->panning;
}
v = synthStartSound(fx->macro, fx->priority, fx->maxVoices, fx->key | 0x80, vol, pan, 0xFF,
0xFF, 0, 0, 0xFF, fx->vGroup, 0, studio, itd);
}
return v;
}

View File

@ -1,21 +1,285 @@
#include "musyx/assert.h"
#include "musyx/musyx_priv.h" #include "musyx/musyx_priv.h"
static VS vs;
void vsInit() { void vsInit() {
u32 i; u32 i;
vs._0 = 0; vs.numBuffers = 0;
for (i = 0; i < 64; i++) { for (i = 0; i < 64; i++) {
vs._908[i] = 0xFF; vs.voices[i] = 0xFF;
} }
vs._948 = 0; vs.nextInstID = 0;
vs._94c = 0; vs.callback = NULL;
} }
void vsSampleStartNotify() { u16 vsNewInstanceID() {
u8 i; // r31
u16 instID; // r29
do {
instID = vs.nextInstID++;
i = 0;
for (; i < vs.numBuffers; ++i) {
if (vs.streamBuffer[i].state != 0 && vs.streamBuffer[i].info.instID == instID) {
break;
}
}
} while (i != vs.numBuffers);
return instID;
} }
void vsSampleEndNotify() { u8 vsAllocateBuffer() {
u8 i;
for (i = 0; i < vs.numBuffers; ++i) {
if (vs.streamBuffer[i].state != 0) {
continue;
}
vs.streamBuffer[i].state = 1;
vs.streamBuffer[i].last = 0;
return i;
}
return 0xFF;
}
void vsFreeBuffer(u8 bufferIndex) {
vs.streamBuffer[bufferIndex].state = 0;
vs.voices[vs.streamBuffer[bufferIndex].voice] = 0xFF;
}
u32 vsSampleStartNotify(unsigned char voice) {
u8 sb; // r29
u8 i; // r28
u32 addr; // r27
for (i = 0; i < vs.numBuffers; ++i) {
if (vs.streamBuffer[i].state != 0 && vs.streamBuffer[i].voice == voice) {
vsFreeBuffer(i);
}
}
sb = vs.voices[voice] = vsAllocateBuffer();
if (sb != 0xFF) {
addr = aramGetStreamBufferAddress(vs.voices[voice], 0);
hwSetVirtualSampleLoopBuffer(voice, addr, vs.bufferLength);
vs.streamBuffer[sb].info.smpID = hwGetSampleID(voice);
vs.streamBuffer[sb].info.instID = vsNewInstanceID();
vs.streamBuffer[sb].smpType = hwGetSampleType(voice);
vs.streamBuffer[sb].voice = voice;
if (vs.callback != NULL) {
vs.callback(0, &vs.streamBuffer[sb].info);
return (vs.streamBuffer[sb].info.instID << 8) | voice;
}
hwSetVirtualSampleLoopBuffer(voice, 0, 0);
} else {
hwSetVirtualSampleLoopBuffer(voice, 0, 0);
}
return 0xFFFFFFFF;
}
void vsSampleEndNotify(unsigned long pubID) {
u8 sb;
u8 voice;
if (pubID != 0xFFFFFFFF) {
u8 id = (u8)pubID;
sb = vs.voices[id];
if (sb != 0xFF) {
if (vs.streamBuffer[sb].info.instID == ((pubID >> 8) & 0xFFFF)) {
if (vs.callback != NULL) {
vs.callback(2, &vs.streamBuffer[sb].info);
}
vsFreeBuffer(sb);
}
}
}
}
void vsUpdateBuffer(struct VS_BUFFER* sb, unsigned long cpos) {
u32 len; // r29
u32 off; // r27
if (sb->last == cpos) {
return;
}
if ((s32)sb->last < cpos) {
if ((s8)sb->smpType != 5) {
cpos = cpos;
} else {
sb->info.data.update.off1 = (sb->last / 14) * 8;
sb->info.data.update.len1 = cpos - sb->last;
sb->info.data.update.off2 = 0;
sb->info.data.update.len2 = 0;
if ((len = vs.callback(1, &sb->info)) != 0) {
off = sb->last + len;
sb->last = off - (off / vs.bufferLength) * vs.bufferLength;
}
}
} else if (cpos == 0) {
if ((s8)sb->smpType != 5) {
cpos = cpos;
} else {
sb->info.data.update.off1 = (sb->last / 14) * 8;
sb->info.data.update.len1 = vs.bufferLength - sb->last;
sb->info.data.update.off2 = 0;
sb->info.data.update.len2 = 0;
if ((len = vs.callback(1, &sb->info)) != 0) {
off = sb->last + len;
sb->last = off - (off / vs.bufferLength) * vs.bufferLength;
}
}
} else if ((s8)sb->smpType != 5) {
cpos = cpos;
} else {
sb->info.data.update.off1 = (sb->last / 14) * 8;
sb->info.data.update.len1 = vs.bufferLength - sb->last;
sb->info.data.update.off2 = 0;
sb->info.data.update.len2 = cpos;
if ((len = vs.callback(1, &sb->info)) != 0) {
off = sb->last + len;
sb->last = off - (off / vs.bufferLength) * vs.bufferLength;
}
}
}
void vsSampleUpdates() {
u32 i; // r29
u32 cpos; // r27
u32 realCPos; // r28
VS_BUFFER* sb; // r31
u32 nextSamples; // r26
}
unsigned long sndVirtualSampleAllocateBuffers(unsigned char numInstances,
unsigned long numSamples) {
long i; // r31
unsigned long len; // r28
#line 437
ASSERT_MSG(sndActive, "Sound system is not initialized.");
ASSERT_MSG(numInstances <= 64, "Parameter exceeded maximum number of instances allowable");
#line 159
hwDisableIrq();
vs.numBuffers = numInstances;
len = sndStreamAllocLength(numSamples, 1);
vs.bufferLength = (len / 8) * 14;
for (i = 0; i < vs.numBuffers; ++i) {
if ((vs.streamBuffer[i].hwId = aramAllocateStreamBuffer(len)) == 0xFF) {
break;
}
vs.streamBuffer[i].state = 0;
vs.voices[vs.streamBuffer[i].voice] = 0xFF;
}
if (i >= vs.numBuffers) {
hwEnableIrq();
return 1;
}
while ((i - 1) > 0) {
aramFreeStreamBuffer(vs.streamBuffer[i - 1].hwId);
--i;
}
hwEnableIrq();
return 0;
}
void sndVirtualSampleFreeBuffers() {
u8 i; // r31
#line 481
ASSERT_MSG(sndActive, "Sound system is not initialized.");
for (i = 0; i < vs.numBuffers; ++i) {
aramFreeStreamBuffer(vs.streamBuffer[i].hwId);
}
vs.numBuffers = 0;
}
void sndVirtualSampleSetCallback(unsigned long (*callback)(unsigned char,
struct SND_VIRTUALSAMPLE_INFO*)) {
#line 0x1ed
ASSERT_MSG(sndActive, "Sound system is not initialized.");
vs.callback = callback;
}
void vsARAMDMACallback(unsigned long user) {
if (vs.callback == NULL) {
return;
}
vs.callback(3, &((VS_BUFFER*)user)->info);
}
void sndVirtualSampleARAMUpdate(unsigned short instID, void* base, unsigned long off1,
unsigned long len1, unsigned long off2, unsigned long len2) {
u8 i;
#line 0x203
ASSERT_MSG(sndActive, "Sound system is not initialized.");
hwDisableIrq();
for (i = 0; i < vs.numBuffers; ++i) {
if (vs.streamBuffer[i].state == 0 || vs.streamBuffer[i].info.instID != instID) {
continue;
}
if ((s32)vs.streamBuffer[i].smpType != 5) {
i = i;
} else {
off1 = (off1 / 14) * 8;
len1 = ((len1 + 13) / 14) * 8;
off2 = (off2 / 14) * 8;
len2 = ((len2 + 13) / 14) * 8;
}
if (len1 != 0) {
hwFlushStream(base, off1, len1, vs.streamBuffer[i].hwId, vsARAMDMACallback,
&vs.streamBuffer[i]);
}
if (len2 != 0) {
hwFlushStream(base, off2, len2, vs.streamBuffer[i].hwId, vsARAMDMACallback,
&vs.streamBuffer[i]);
}
if (vs.streamBuffer[i].smpType == 5) {
hwSetStreamLoopPS(vs.streamBuffer[i].voice, *(u32*)(OSCachedToUncached(base)) >> 24);
}
break;
}
hwEnableIrq();
}
void sndVirtualSampleEndPlayback(unsigned short instID) {
u8 i; // r30
VS_BUFFER* stream; // r31
u32 cpos; // r28
hwDisableIrq();
for (i = 0; i < vs.numBuffers; ++i) {
if (vs.streamBuffer[i].state == 0 || vs.streamBuffer[i].info.instID != instID) {
continue;
}
stream = &vs.streamBuffer[i];
cpos = hwGetPos(i);
if (stream->last < cpos) {
stream->finalGoodSamples = vs.bufferLength - (cpos - stream->last);
} else {
stream->finalGoodSamples = stream->last - cpos;
}
stream->finalLast = cpos;
stream->state = 2;
break;
}
hwEnableIrq();
} }

View File

@ -0,0 +1,492 @@
#include "musyx/assert.h"
#include "musyx/musyx_priv.h"
void voiceResetLastStarted(SYNTH_VOICE* svoice);
static VID_LIST vidList[128];
static u8 synth_last_started[8][16];
static u8 synth_last_fxstarted[64];
SYNTH_VOICELIST voiceList[64];
SYNTH_ROOTLIST voicePrioSortRootList[256];
u8 voicePrioSortVoicesRoot[256];
SYNTH_VOICELIST voicePrioSortVoices[64];
static u32 vidCurrentId = 0;
static VID_LIST* vidRoot = NULL;
static VID_LIST* vidFree = NULL;
u16 voicePrioSortRootListRoot = 0;
u8 voiceMusicRunning = 0;
u8 voiceFxRunning = 0;
u8 voiceListInsert = 0;
u8 voiceListRoot = 0;
void vidInit() {
int i;
VID_LIST* lvl;
vidCurrentId = 0;
vidRoot = NULL;
vidFree = vidList;
for (lvl = NULL, i = 0; i < 128; lvl = &vidList[i], ++i) {
vidList[i].prev = lvl;
if (lvl != NULL) {
lvl->next = &vidList[i];
}
}
lvl->next = NULL;
}
VID_LIST* get_vidlist(u32 vid) {
VID_LIST* vl = vidRoot;
while (vl != NULL) {
if (vl->vid == vid) {
return vl;
}
if (vl->vid > vid) {
break;
}
vl = vl->next;
}
return NULL;
}
u32 get_newvid() {
u32 vid; // r31
do {
vid = vidCurrentId++;
} while (vid == 0xFFFFFFFF);
return vid;
}
void vidRemove(VID_LIST** vidList) {
if ((*vidList)->prev != NULL) {
(*vidList)->prev->next = (*vidList)->next;
} else {
vidRoot = (*vidList)->next;
}
if ((*vidList)->next != NULL) {
(*vidList)->next->prev = (*vidList)->prev;
}
(*vidList)->next = vidFree;
if (vidFree != NULL) {
vidFree->prev = *vidList;
}
(*vidList)->prev = NULL;
vidFree = *vidList;
*vidList = NULL;
}
void vidRemoveVoiceReferences(SYNTH_VOICE* svoice) {
if (svoice->id == 0xFFFFFFFF) {
return;
}
voiceResetLastStarted(svoice);
if (svoice->parent != 0xFFFFFFFF) {
synthVoice[svoice->parent & 0xFF].child = svoice->child;
if (svoice->child != 0xFFFFFFFF) {
synthVoice[svoice->child & 0xFF].parent = svoice->parent;
}
vidRemove(&svoice->vidList);
} else if (svoice->child != 0xFFFFFFFF) {
svoice->vidList->root = svoice->child;
synthVoice[svoice->child & 0xFF].parent = 0xFFFFFFFF;
synthVoice[svoice->child & 0xFF].vidMasterList = svoice->vidMasterList;
if (svoice->vidList != svoice->vidMasterList) {
vidRemove(&svoice->vidList);
}
svoice->vidMasterList = svoice->vidList = NULL;
} else if (svoice->vidList != svoice->vidMasterList) {
vidRemove(&svoice->vidList);
vidRemove(&svoice->vidMasterList);
} else {
vidRemove(&svoice->vidList);
svoice->vidMasterList = NULL;
}
}
unsigned long vidMakeRoot(struct SYNTH_VOICE* svoice) {
svoice->vidMasterList = svoice->vidList;
return svoice->vidList->vid;
}
u32 vidMakeNew(SYNTH_VOICE* svoice, u32 isMaster) {
u32 vid; // r29
VID_LIST* nvl; // r30
VID_LIST* lvl; // r28
VID_LIST* vl; // r31
vid = get_newvid();
lvl = NULL;
nvl = vidRoot;
while (nvl != NULL) {
if (nvl->vid > vid) {
break;
}
if (nvl->vid == vid) {
vid = get_newvid();
}
lvl = nvl;
nvl = nvl->next;
}
if ((vl = vidFree) == NULL) {
return 0xFFFFFFFF;
}
if ((vidFree = vidFree->next) != NULL) {
vidFree->prev = NULL;
}
if (lvl == NULL) {
vidRoot = vl;
} else {
lvl->next = vl;
}
vl->prev = lvl;
vl->next = nvl;
if (nvl != NULL) {
nvl->prev = vl;
}
vl->vid = vid;
vl->root = svoice->id;
svoice->vidMasterList = isMaster ? vl : NULL;
svoice->vidList = vl;
if (isMaster != 0) {
return vid;
}
return svoice->id;
}
u32 vidGetInternalId(u32 vid) {
VID_LIST* vl;
if (vid != 0xffffffff) {
if ((vl = get_vidlist(vid)) != NULL) {
return vl->root;
}
}
return 0xffffffff;
}
void voiceInitPrioSort() {
u32 i;
for (i = 0; i < synthInfo.voiceNum; ++i) {
voicePrioSortVoices[i].user = 0;
}
for (i = 0; i < 256; ++i) {
voicePrioSortVoicesRoot[i] = 0xff;
}
voicePrioSortRootListRoot = 0xffff;
}
void voiceRemovePriority(SYNTH_VOICE* svoice) {
SYNTH_VOICELIST* vps = &voicePrioSortVoices[svoice->id & 0xFF]; // r31
SYNTH_ROOTLIST* rps; // r30
if (vps->user != 1) {
return;
}
if (vps->prev != 0xff) {
voicePrioSortVoices[vps->prev].next = vps->next;
} else {
voicePrioSortVoicesRoot[svoice->prio] = vps->next;
}
if (vps->next != 0xff) {
voicePrioSortVoices[vps->next].prev = vps->prev;
} else if (vps->prev == 0xFF) {
rps = &voicePrioSortRootList[svoice->prio];
if (rps->prev != 0xFFFF) {
voicePrioSortRootList[rps->prev].next = rps->next;
} else {
voicePrioSortRootListRoot = rps->next;
}
if (rps->next != 0xFFFF) {
voicePrioSortRootList[rps->next].prev = rps->prev;
}
}
vps->user = 0;
}
#pragma dont_inline on
void voiceSetPriority(SYNTH_VOICE* svoice, u8 prio) {
u16 i; // r29
u16 li; // r25
SYNTH_VOICELIST* vps; // r27
u32 v; // r26
}
u32 voiceAllocate(u8 priority, u8 maxVoices, u16 allocId, u8 fxFlag) {
long i; // r31
long num; // r26
long voice; // r30
u16 p; // r29
u32 type_alloc; // r25
SYNTH_VOICELIST* sfv; // r27
}
#pragma dont_inline reset
void voiceFree(SYNTH_VOICE* svoice) {
u32 i; // r29
SYNTH_VOICELIST* sfv; // r30
#line 628
ASSERT(svoice->id != 0xFFFFFFFF);
#line 256
macMakeInactive(svoice, MAC_STATE_STOPPED);
voiceRemovePriority(svoice);
svoice->addr = NULL;
svoice->prio = 0;
sfv = &voiceList[(i = svoice->id & 0xFF)];
if (sfv->user == 0) {
sfv->user = 1;
if (voiceListRoot != 0xFF) {
sfv->next = 0xFF;
sfv->prev = voiceListInsert;
voiceList[voiceListInsert].next = i;
} else {
sfv->next = 0xFF;
sfv->prev = 0xFF;
voiceListRoot = i;
}
voiceListInsert = i;
if (svoice->fxFlag != 0) {
--voiceFxRunning;
} else {
--voiceMusicRunning;
}
}
svoice->id = 0xFFFFFFFF;
}
void voiceInitFreeList() {
u32 i; // r31
for (i = 0; i < synthInfo.voiceNum; ++i) {
voiceList[i].prev = i - 1;
voiceList[i].next = i + 1;
voiceList[i].user = 1;
}
voiceList[0].prev = 0xff;
voiceList[synthInfo.voiceNum - 1].next = 0xff;
voiceListRoot = 0;
voiceListInsert = synthInfo.voiceNum - 1;
}
void synthInitAllocationAids() {
voiceInitFreeList();
voiceInitPrioSort();
voiceFxRunning = 0;
voiceMusicRunning = 0;
}
u32 voiceBlock(unsigned char prio) {
u32 voice = voiceAllocate(prio, 0xFF, 0xFFFF, 1);
if (voice != 0xFFFFFFFF) {
synthVoice[voice].block = 1;
synthVoice[voice].fxFlag = 1;
#ifdef PRIME1
synthVoice[voice].allocId = 0xFFFF;
#endif
vidRemoveVoiceReferences(&synthVoice[voice]);
synthVoice[voice].id = voice | 0xFFFFFF00;
if (hwIsActive(voice)) {
hwBreak(voice);
}
macMakeInactive(&synthVoice[voice], MAC_STATE_STOPPED);
synthVoice[voice].addr = NULL;
voiceSetPriority(&synthVoice[voice], prio);
}
return voice;
}
void voiceUnblock(u32 voice) {
if (voice == 0xFFFFFFFF) {
return;
}
if (hwIsActive(voice)) {
hwBreak(voice);
}
synthVoice[voice].id = voice;
voiceFree(&synthVoice[voice]);
synthVoice[voice].block = 0;
}
void voiceKill(u32 vi) {
SYNTH_VOICE* sv = &synthVoice[vi]; // r31
if (sv->addr != NULL) {
vidRemoveVoiceReferences(sv);
sv->cFlags &= ~3;
sv->age = 0;
voiceFree(sv);
}
if (sv->block != 0) {
streamKill(vi);
}
hwBreak(vi);
}
long voiceKillSound(u32 voiceid) {
long ret;
u32 next_voiceid;
u32 i;
u32 vid;
ret = -1;
if (sndActive != FALSE) {
i = vidGetInternalId(voiceid);
while (i != 0xFFFFFFFF) {
vid = i & 0xFF;
next_voiceid = synthVoice[vid].child;
if (i == synthVoice[vid].id) {
voiceKill(vid);
ret = 0;
}
i = next_voiceid;
}
}
return ret;
}
void synthKillAllVoices(unsigned char musiconly) {
u32 i;
for (i = 0; i < synthInfo.voiceNum; ++i) {
if (synthVoice[i].addr != NULL) {
if (musiconly == 0 || (musiconly != 0 && synthVoice[i].fxFlag == 0)) {
voiceKill(i);
}
} else {
voiceKill(i);
}
}
}
void synthKillVoicesByMacroReferences(u16* ref) {
u32 i; // r31
u16 id; // r29
for (i = 0; i < synthInfo.voiceNum; ++i) {
if (synthVoice[i].addr == NULL && synthVoice[i].block == 0) {
voiceKill(i);
}
}
while (*ref != 0xFFFF) {
if ((*ref & 0x8000)) {
id = *ref & 0x3fff;
while (id <= ref[1]) {
for (i = 0; i < synthInfo.voiceNum; ++i) {
if (synthVoice[i].addr != NULL && id == synthVoice[i].macroId) {
voiceKill(i);
}
}
++id;
}
ref += 2;
} else {
for (i = 0; i < synthInfo.voiceNum; ++i) {
if (synthVoice[i].addr != NULL && *ref == synthVoice[i].macroId) {
voiceKill(i);
}
}
++ref;
}
}
}
u32 voiceIsLastStarted(SYNTH_VOICE* svoice) {
u32 i; // r31
if (svoice->id != 0xFFFFFFFF && svoice->midi != 0xFF) {
i = svoice->id & 0xFF;
if (svoice->midiSet == 0xFF) {
if (synth_last_fxstarted[i] == i) {
return TRUE;
}
} else if (synth_last_started[svoice->midiSet][svoice->midi] == i) {
return TRUE;
}
}
return FALSE;
}
void voiceSetLastStarted(SYNTH_VOICE* svoice) {
u32 i; // r31
if (svoice->id != 0xFFFFFFFF && svoice->midi != 0xFF) {
i = svoice->id & 0xFF;
if (svoice->midiSet == 0xFF) {
synth_last_fxstarted[i] = i;
} else {
synth_last_started[svoice->midiSet][svoice->midi] = i;
}
}
}
void voiceResetLastStarted(struct SYNTH_VOICE* svoice) {
u32 i;
if ((svoice->id != 0xffffffff) && (svoice->midi != 0xff)) {
i = svoice->id & 0xff;
if (svoice->midiSet == 0xff) {
if (synth_last_fxstarted[i] == i) {
synth_last_fxstarted[i] = 0xff;
}
} else if (i == synth_last_started[svoice->midiSet][svoice->midi]) {
synth_last_started[svoice->midiSet][svoice->midi] = 0xff;
}
}
}
void voiceInitLastStarted() {
u32 i;
u32 j;
for (i = 0; i < 8; ++i) {
for (j = 0; j < 16; ++j) {
synth_last_started[i][j] = 0xFF;
}
}
for (j = 0; j < 64; ++j) {
synth_last_fxstarted[j] = 0xFF;
}
}