mirror of https://github.com/PrimeDecomp/prime.git
parent
6c1eb3ecf4
commit
f94589c769
|
@ -18,7 +18,7 @@ typedef struct ARR {
|
||||||
u32 tsTab; // offset 0x54, size 0x4
|
u32 tsTab; // offset 0x54, size 0x4
|
||||||
} ARR;
|
} ARR;
|
||||||
|
|
||||||
#define ARR_GET(arr, offset) ((void*)(offset + (u32)arr))
|
#define ARR_GET(arr, offset) ((void*)(offset + (uintptr_t)arr))
|
||||||
#define ARR_GET_TYPE(arr, offset, ty) ((ty)ARR_GET(arr, offset))
|
#define ARR_GET_TYPE(arr, offset, ty) ((ty)ARR_GET(arr, offset))
|
||||||
|
|
||||||
typedef struct TENTRY {
|
typedef struct TENTRY {
|
||||||
|
@ -102,7 +102,7 @@ typedef struct SEQ_EVENT {
|
||||||
|
|
||||||
typedef struct MTRACK_DATA {
|
typedef struct MTRACK_DATA {
|
||||||
// total size: 0x8
|
// total size: 0x8
|
||||||
u32 time; // offset 0x0, size 0x4
|
volatile u32 time; // offset 0x0, size 0x4
|
||||||
u32 bpm; // offset 0x4, size 0x4
|
u32 bpm; // offset 0x4, size 0x4
|
||||||
} MTRACK_DATA;
|
} MTRACK_DATA;
|
||||||
|
|
||||||
|
@ -114,8 +114,8 @@ typedef struct MTRACK {
|
||||||
|
|
||||||
typedef struct TICKS {
|
typedef struct TICKS {
|
||||||
// total size: 0x8
|
// total size: 0x8
|
||||||
u32 low; // offset 0x0, size 0x4
|
u32 low; // offset 0x0, size 0x4
|
||||||
long high; // offset 0x4, size 0x4
|
s32 high; // offset 0x4, size 0x4
|
||||||
} TICKS;
|
} TICKS;
|
||||||
|
|
||||||
typedef struct SEQ_SECTION {
|
typedef struct SEQ_SECTION {
|
||||||
|
|
|
@ -23,8 +23,11 @@ bool synthFXSetCtrl(SND_VOICEID vid, u8 ctrl, u8 value);
|
||||||
bool synthFXSetCtrl14(SND_VOICEID vid, u8 ctrl, u16 value);
|
bool synthFXSetCtrl14(SND_VOICEID vid, u8 ctrl, u16 value);
|
||||||
bool synthSendKeyOff(SND_VOICEID vid);
|
bool synthSendKeyOff(SND_VOICEID vid);
|
||||||
SND_VOICEID synthFXStart(u16 fid, u8 vol, u8 pan, u8 studio, u32 itd);
|
SND_VOICEID synthFXStart(u16 fid, u8 vol, u8 pan, u8 studio, u32 itd);
|
||||||
void synthVolume(unsigned char volume, unsigned short time, unsigned char vGroup,
|
void synthVolume(u8 volume, u16 time, u8 vGroup, u8 seqMode, u32 seqId);
|
||||||
unsigned char seqMode, unsigned long seqId);
|
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);
|
||||||
|
bool synthIsFadeOutActive(u8 vGroup);
|
||||||
|
|
||||||
/* TODO: Move this where it belongs */
|
/* TODO: Move this where it belongs */
|
||||||
void hwSetAUXProcessingCallbacks(u8 studio, SND_AUX_CALLBACK auxA, void* userA,
|
void hwSetAUXProcessingCallbacks(u8 studio, SND_AUX_CALLBACK auxA, void* userA,
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
#include "GuiSys/CAuiMain.hpp"
|
#include "GuiSys/CAuiMain.hpp"
|
||||||
|
|
||||||
void InitializeApplicationUI(CGuiSys&) {
|
void InitializeApplicationUI(CGuiSys&) {}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ u16 seqMIDIPriority[8][16];
|
||||||
static SEQ_INSTANCE* cseq = NULL;
|
static SEQ_INSTANCE* cseq = NULL;
|
||||||
static NOTE* noteFree = NULL;
|
static NOTE* noteFree = NULL;
|
||||||
static u32 curSeqId = 0;
|
static u32 curSeqId = 0;
|
||||||
static u8 curFadeOutState = 0;
|
static bool8 curFadeOutState = 0;
|
||||||
static u32 seq_next_id = 0;
|
static u32 seq_next_id = 0;
|
||||||
struct SEQ_INSTANCE* seqFreeRoot = NULL;
|
struct SEQ_INSTANCE* seqFreeRoot = NULL;
|
||||||
struct SEQ_INSTANCE* seqActiveRoot = NULL;
|
struct SEQ_INSTANCE* seqActiveRoot = NULL;
|
||||||
|
@ -488,8 +488,8 @@ u32 seqStartPlay(PAGE* norm, PAGE* drum, MIDISETUP* midiSetup, u32* song, SND_PL
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SetTickDelta(SEQ_SECTION* section, u32 deltaTime) {
|
static void SetTickDelta(SEQ_SECTION* section, u32 deltaTime) {
|
||||||
float tickDelta = (float)section->bpm * (float)deltaTime * 0.0000000244140619f;
|
float tickDelta = (float)section->bpm * (float)deltaTime * (1.f / 4096.f);
|
||||||
tickDelta *= section->speed * 0.00390625f;
|
tickDelta *= section->speed * (1.f / 256.f);
|
||||||
|
|
||||||
section->tickDelta[section->timeIndex].low = fmodf(tickDelta * 65536.f, 65536.f);
|
section->tickDelta[section->timeIndex].low = fmodf(tickDelta * 65536.f, 65536.f);
|
||||||
section->tickDelta[section->timeIndex].high = floorf(tickDelta);
|
section->tickDelta[section->timeIndex].high = floorf(tickDelta);
|
||||||
|
@ -497,25 +497,23 @@ static void SetTickDelta(SEQ_SECTION* section, u32 deltaTime) {
|
||||||
|
|
||||||
static void HandleMasterTrack(u8 secIndex) {
|
static void HandleMasterTrack(u8 secIndex) {
|
||||||
SEQ_SECTION* section; // r31
|
SEQ_SECTION* section; // r31
|
||||||
|
|
||||||
section = &cseq->section[secIndex];
|
section = &cseq->section[secIndex];
|
||||||
|
if (section->mTrack.base != NULL) {
|
||||||
|
while (section->mTrack.addr->time != -1) {
|
||||||
|
if (section->mTrack.addr->time > section->time[section->timeIndex].high) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (section->mTrack.base == NULL) {
|
if ((cseq->arrbase->info & 0x40000000) != 0) {
|
||||||
return;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
while (section->mTrack.addr->time != -1) {
|
++section->mTrack.addr;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1064,18 +1062,134 @@ static SEQ_EVENT* GetGlobalEvent(SEQ_SECTION* section) {
|
||||||
return ev;
|
return ev;
|
||||||
}
|
}
|
||||||
|
|
||||||
static SEQ_EVENT* HandleEvent(SEQ_EVENT* event, unsigned char secIndex, unsigned long* loopFlag) {
|
static SEQ_EVENT* HandleEvent(SEQ_EVENT* event, u8 secIndex, u32* loopFlag) {
|
||||||
struct CPAT* pa; // r26
|
CPAT* pa; // r26
|
||||||
struct NOTE_DATA* pe; // r24
|
NOTE_DATA* pe; // r24
|
||||||
long velocity; // r28
|
s32 velocity; // r28
|
||||||
long key; // r30
|
s32 key; // r30
|
||||||
unsigned char midi; // r27
|
u8 midi; // r27
|
||||||
unsigned short macId; // r21
|
u16 macId; // r21
|
||||||
struct NOTE* note; // r22
|
NOTE* note; // r22
|
||||||
struct TENTRY* tEntry; // r25
|
TENTRY* tEntry; // r25
|
||||||
struct CPAT* pattern; // r29
|
CPAT* pattern; // r29
|
||||||
unsigned long* pTab; // r20
|
u32* pTab; // r20
|
||||||
struct SEQ_PATTERN* pptr; // r23
|
SEQ_PATTERN* pptr; // r23
|
||||||
|
|
||||||
|
switch (event->type) {
|
||||||
|
case 4:
|
||||||
|
tEntry = event->info.trackAddr;
|
||||||
|
pattern = &cseq->pattern[event->trackId];
|
||||||
|
pTab = ARR_GET(cseq->arrbase, cseq->arrbase->pTab);
|
||||||
|
pptr = ARR_GET(cseq->arrbase, pTab[tEntry->pattern]);
|
||||||
|
pattern->addr = (NOTE_DATA*)&pptr->noteData;
|
||||||
|
pattern->lTime = 0;
|
||||||
|
pattern->baseTime = tEntry->time;
|
||||||
|
pattern->patternInfo = tEntry;
|
||||||
|
InitStream(&pattern->pitchBend, pptr->pitchBend);
|
||||||
|
pattern->pitchBend.value = 0x2000;
|
||||||
|
InitStream(&pattern->modulation, pptr->modulation);
|
||||||
|
pattern->modulation.value = 0;
|
||||||
|
pattern->midi = ARR_GET_TYPE(cseq->arrbase, cseq->arrbase->tmTab, u8*)[event->trackId];
|
||||||
|
if (tEntry->prgChange != 0xff) {
|
||||||
|
DoPrgChange(cseq, tEntry->prgChange, pattern->midi);
|
||||||
|
}
|
||||||
|
if (tEntry->velocity != 0xff) {
|
||||||
|
inpSetMidiCtrl(SND_MIDICTRL_VOLUME, pattern->midi, curSeqId, tEntry->velocity);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0:
|
||||||
|
pe = event->info.pattern.addr;
|
||||||
|
pa = event->info.pattern.base;
|
||||||
|
key = pe->key;
|
||||||
|
velocity = pe->velocity;
|
||||||
|
midi = pa->midi;
|
||||||
|
|
||||||
|
if ((key & 0x80) != 0) {
|
||||||
|
switch (velocity) {
|
||||||
|
case 0:
|
||||||
|
DoPrgChange(cseq, key & 0x7f, midi);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
inpSetMidiCtrl(0x82 /* TODO SND_MIDICTRL_? */, midi, curSeqId, key & 0x7f);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if ((velocity & 0x80) != 0x80) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
switch (velocity & 0x7f) {
|
||||||
|
case 0x68:
|
||||||
|
if (cseq->syncActive) {
|
||||||
|
seqCrossFade(&cseq->syncCrossInfo, cseq->syncSeqIdPtr, TRUE);
|
||||||
|
cseq->syncActive = FALSE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0x69:
|
||||||
|
seqMIDIPriority[curSeqId][midi] = key & 0x7f;
|
||||||
|
break;
|
||||||
|
case 0x6a:
|
||||||
|
seqMIDIPriority[curSeqId][midi] = (key & 0x7f) + 0x80;
|
||||||
|
break;
|
||||||
|
case 0x79:
|
||||||
|
inpResetMidiCtrl(midi, curSeqId, FALSE);
|
||||||
|
break;
|
||||||
|
case 0x7b:
|
||||||
|
KeyOffNotes();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// case 0x6b:
|
||||||
|
inpSetMidiCtrl(velocity & 0x7f, midi, curSeqId, key & 0x7f);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((cseq->trackMute[event->trackId / 32] & (1 << (event->trackId & 0x1f))) != 0) {
|
||||||
|
if ((macId = cseq->prgState[midi].macId) != 0xffff) {
|
||||||
|
key += pa->patternInfo->transpose;
|
||||||
|
if (key > 0x7f) {
|
||||||
|
key = 0x7f;
|
||||||
|
} else if (key < 0) {
|
||||||
|
key = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
velocity += pa->patternInfo->velocityAdd;
|
||||||
|
if (velocity > 0x7f) {
|
||||||
|
velocity = 0x7f;
|
||||||
|
} else if (velocity < 0) {
|
||||||
|
velocity = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((note = AllocateNote(event->time + pe->length, secIndex)) != NULL) {
|
||||||
|
if ((note->id = synthStartSound(
|
||||||
|
macId, cseq->prgState[midi].priority, cseq->prgState[midi].maxVoices, key,
|
||||||
|
velocity, 64, midi, curSeqId, secIndex, 0, event->trackId,
|
||||||
|
cseq->trackVolGroup[event->trackId], curFadeOutState ? -1 : 0, cseq->defStudio,
|
||||||
|
synthITDDefault[cseq->defStudio].music)) == SND_ID_ERROR) {
|
||||||
|
FreeNote(note);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
pa = event->info.pattern.base;
|
||||||
|
inpSetMidiCtrl14(SND_MIDICTRL_PITCHBEND, pa->midi, curSeqId, HandleStream(&pa->pitchBend));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
pa = event->info.pattern.base;
|
||||||
|
inpSetMidiCtrl14(SND_MIDICTRL_MODULATION, pa->midi, curSeqId, HandleStream(&pa->modulation));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
*loopFlag |= 1;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return GenerateNextTrackEvent(event->trackId);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void InitTrackEvents() {
|
static void InitTrackEvents() {
|
||||||
|
@ -1097,7 +1211,7 @@ static void InitTrackEvents() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void InitTrackEventsSection(unsigned char secIndex) {
|
static void InitTrackEventsSection(u8 secIndex) {
|
||||||
u32 i; // r31
|
u32 i; // r31
|
||||||
SEQ_EVENT* ev; // r30
|
SEQ_EVENT* ev; // r30
|
||||||
|
|
||||||
|
@ -1116,25 +1230,133 @@ static void InitTrackEventsSection(unsigned char secIndex) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned long HandleTrackEvents(unsigned char secIndex, unsigned long deltaTime) {
|
static bool HandleTrackEvents(u8 secIndex, u32 deltaTime) {
|
||||||
struct SEQ_EVENT* ev; // r29
|
SEQ_EVENT* ev; // r29
|
||||||
unsigned long loopFlag; // r1+0x10
|
bool loopFlag; // r1+0x10
|
||||||
struct SEQ_SECTION* section; // r31
|
SEQ_SECTION* section; // r31
|
||||||
|
|
||||||
return FALSE;
|
section = &cseq->section[secIndex];
|
||||||
|
loopFlag = FALSE;
|
||||||
|
|
||||||
|
while (GetNextEventTime(section) <= section->time[section->timeIndex].high) {
|
||||||
|
if ((ev = GetGlobalEvent(section)) == NULL) {
|
||||||
|
if (!loopFlag) {
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
loopFlag = FALSE;
|
||||||
|
section->timeIndex ^= 1;
|
||||||
|
section->time[section->timeIndex].high = cseq->arrbase->loopPoint[secIndex];
|
||||||
|
section->time[section->timeIndex].low = section->time[section->timeIndex ^ 1].low;
|
||||||
|
RewindMTrack(secIndex, deltaTime);
|
||||||
|
section->loopCnt += 1;
|
||||||
|
InitTrackEventsSection(secIndex);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((ev = HandleEvent(ev, secIndex, &loopFlag)) != NULL) {
|
||||||
|
InsertGlobalEvent(section, ev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void seqHandle(unsigned long deltaTime) {
|
void seqHandle(u32 deltaTime) {
|
||||||
unsigned long x; // r29
|
u32 x; // r29
|
||||||
unsigned long i; // r31
|
u32 i; // r31
|
||||||
unsigned long j; // r28
|
u32 j; // r28
|
||||||
unsigned long eventsActive; // r25
|
u32 eventsActive; // r25
|
||||||
unsigned long notesActive; // r24
|
u32 notesActive; // r24
|
||||||
struct SEQ_INSTANCE* si; // r30
|
SEQ_INSTANCE* si; // r30
|
||||||
struct SEQ_INSTANCE* nextSi; // r27
|
SEQ_INSTANCE* nextSi; // r27
|
||||||
|
|
||||||
|
if (deltaTime == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
si = seqActiveRoot;
|
||||||
|
while (si != NULL) {
|
||||||
|
nextSi = si->next;
|
||||||
|
cseq = si;
|
||||||
|
curSeqId = si->index;
|
||||||
|
curFadeOutState = synthIsFadeOutActive(si->defVGroup);
|
||||||
|
|
||||||
|
if (cseq->trackSectionTab == NULL) {
|
||||||
|
HandleMasterTrack(0);
|
||||||
|
SetTickDelta(cseq->section, deltaTime);
|
||||||
|
eventsActive = HandleTrackEvents(0, deltaTime);
|
||||||
|
notesActive = HandleNotes();
|
||||||
|
HandleKeyOffNotes();
|
||||||
|
|
||||||
|
for (i = 0; i < 2; ++i) {
|
||||||
|
x = cseq->section[0].time[i].low + cseq->section[0].tickDelta[i].low;
|
||||||
|
cseq->section[0].time[i].low = x & 0xffff;
|
||||||
|
x >>= 16;
|
||||||
|
cseq->section[0].time[i].high += x + cseq->section[0].tickDelta[i].high;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
eventsActive = 0;
|
||||||
|
for (i = 0; i < 16; ++i) {
|
||||||
|
HandleMasterTrack(i);
|
||||||
|
SetTickDelta(&cseq->section[i], deltaTime);
|
||||||
|
eventsActive |= HandleTrackEvents(i, deltaTime);
|
||||||
|
}
|
||||||
|
notesActive = HandleNotes();
|
||||||
|
HandleKeyOffNotes();
|
||||||
|
|
||||||
|
for (i = 0; i < 16; ++i) {
|
||||||
|
for (j = 0; j < 2; ++j) {
|
||||||
|
x = cseq->section[i].time[j].low + cseq->section[i].tickDelta[j].low;
|
||||||
|
cseq->section[i].time[j].low = x & 0xffff;
|
||||||
|
x >>= 16;
|
||||||
|
cseq->section[i].time[j].high += x + cseq->section[i].tickDelta[j].high;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eventsActive == 0 && notesActive == 0) {
|
||||||
|
if (si->prev != NULL) {
|
||||||
|
si->prev->next = nextSi;
|
||||||
|
} else {
|
||||||
|
seqActiveRoot = nextSi;
|
||||||
|
}
|
||||||
|
if (nextSi != NULL) {
|
||||||
|
nextSi->prev = si->prev;
|
||||||
|
}
|
||||||
|
ResetNotes(si);
|
||||||
|
si->state = 0;
|
||||||
|
si->prev = NULL;
|
||||||
|
if ((si->next = seqFreeRoot) != NULL) {
|
||||||
|
seqFreeRoot->prev = si;
|
||||||
|
}
|
||||||
|
seqFreeRoot = si;
|
||||||
|
}
|
||||||
|
si = nextSi;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void seqInit() {
|
void seqInit() {
|
||||||
unsigned long i; // r31
|
u32 i; // r31
|
||||||
unsigned long j; // r29
|
u32 j; // r29
|
||||||
|
|
||||||
|
seqActiveRoot = NULL;
|
||||||
|
seqPausedRoot = NULL;
|
||||||
|
for (i = 0; i < 8; ++i) {
|
||||||
|
if (i == 0) {
|
||||||
|
seqFreeRoot = &seqInstance[i];
|
||||||
|
seqInstance[i].prev = NULL;
|
||||||
|
} else {
|
||||||
|
seqInstance[i - 1].next = &seqInstance[i];
|
||||||
|
seqInstance[i].prev = &seqInstance[i - 1];
|
||||||
|
}
|
||||||
|
seqInstance[i].index = i;
|
||||||
|
seqInstance[i].state = 0;
|
||||||
|
for (j = 0; j < 0x10; ++j) {
|
||||||
|
seqMIDIPriority[i][j] = 0xffff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
seqInstance[i - 1].next = NULL;
|
||||||
|
ClearNotes();
|
||||||
|
InitPublicIds();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue