From 9a51651a8efdff76fe570b1adba3bd6c4f28eb91 Mon Sep 17 00:00:00 2001 From: Banjo Kazooie Date: Mon, 10 Oct 2022 16:34:11 -0500 Subject: [PATCH] core1/done/audio/n_seqplayer.c done --- README.md | 2 +- include/enums.h | 18 +- include/file_and_line.h | 29 + progress/progress_core1.svg | 6 +- progress/progress_core2.svg | 6 +- progress/progress_total.svg | 6 +- src/core1/code_13990.c | 122 +-- src/core1/code_15630.c | 60 ++ src/core1/code_22E40.c | 91 --- src/core1/done/audio/n_seqplayer.c | 1221 ++++++++++++++++++++++++++++ src/core1/n_env.c | 12 + src/core2/code_AEDA0.c | 192 ++++- subyaml/core1.us.v10.yaml | 9 +- symbol_addrs.core1.us.v10.txt | 2 +- 14 files changed, 1565 insertions(+), 211 deletions(-) create mode 100644 include/file_and_line.h create mode 100644 src/core1/code_15630.c delete mode 100644 src/core1/code_22E40.c create mode 100644 src/core1/done/audio/n_seqplayer.c create mode 100644 src/core1/n_env.c diff --git a/README.md b/README.md index a3363778..3d1bf736 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# banjo (89.2214%) +# banjo (89.9076%) diff --git a/include/enums.h b/include/enums.h index 658afe85..b38aedd4 100644 --- a/include/enums.h +++ b/include/enums.h @@ -1,14 +1,14 @@ #ifndef ENUMS_H #define ENUMS_H -#define SPRITE_TYPE_CI4 (1 << 0) -#define SPRITE_TYPE_CI8 (1 << 2) -#define SPRITE_TYPE_I4 (1 << 5) -#define SPRITE_TYPE_I8 (1 << 6) -#define SPRITE_TYPE_IA4 (1 << 7) -#define SPRITE_TYPE_IA8 (1 << 8) -#define SPRITE_TYPE_UNKNOWN_200 (1 << 9) -#define SPRITE_TYPE_RGBA16 (1 << 10) +#define SPRITE_TYPE_CI4 (1 << 0) //0x001 +#define SPRITE_TYPE_CI8 (1 << 2) //0x004 +#define SPRITE_TYPE_I4 (1 << 5) //0x020 +#define SPRITE_TYPE_I8 (1 << 6) //0x040 +#define SPRITE_TYPE_IA4 (1 << 7) //0x080 +#define SPRITE_TYPE_IA8 (1 << 8) //0x100 +#define SPRITE_TYPE_UNKNOWN_200 (1 << 9) //0x200 +#define SPRITE_TYPE_RGBA16 (1 << 10) ////0x400 #define SPRITE_TYPE_RGBA32 (1 << 11) enum bkprog_e{ @@ -3055,7 +3055,7 @@ enum asset_e ASSET_543_MODEL_JINJO_STATUE_BASE = 0x543, ASSET_544_MODEL_JINJONATOR_STATUE_BASE, ASSET_545_MODEL_STONE_JINJO, - ASSET_546_MODEL_GRUNTY_SPELL_BARRIER = 0x546, + ASSET_546_MODEL_GRUNTY_SPELL_BARRIER, // 547 GL Blue Egg Refill Pillow // 548 GL Red Feather Refill Pillow // 549 GL Gold Feather Refill Pillow diff --git a/include/file_and_line.h b/include/file_and_line.h new file mode 100644 index 00000000..6a1551d4 --- /dev/null +++ b/include/file_and_line.h @@ -0,0 +1,29 @@ +#ifndef _FILE_AND_LINE_H_ +#define _FILE_AND_LINE_H_ + +extern void func_8033F000(const char *, const char *, int); + + +#ifdef NONMATCHING + #define LINE(line_num) __LINE__ + #define FILE(file_name) __FILE__ + #define matching_assert(EX, F, L) assert(EX) +#else + #define LINE(line_num) line_num + #define FILE(file_name) "file_name" + #ifdef __ANSI_CPP__ + #define FILE(file_name) # file_name + #else + #define FILE(file_name) "file_name" + #endif + #define matching_assert(EX, F, L) assert(EX) + #ifdef __ANSI_CPP__ + #define matching_assert(EX, F, L) ((EX)?((void)0):func_8033F000( # EX , # F, L)) + #else + #define matching_assert(EX, F , L) ((EX)?((void)0):func_8033F000("EX", "F", L)) + #endif +#endif + + + +#endif \ No newline at end of file diff --git a/progress/progress_core1.svg b/progress/progress_core1.svg index 6f0b5513..4b1ca596 100644 --- a/progress/progress_core1.svg +++ b/progress/progress_core1.svg @@ -9,7 +9,7 @@ - + @@ -17,7 +17,7 @@ core1 - 73.1536% - 73.1536% + 76.3559% + 76.3559% \ No newline at end of file diff --git a/progress/progress_core2.svg b/progress/progress_core2.svg index be4e35dc..9bca07fb 100644 --- a/progress/progress_core2.svg +++ b/progress/progress_core2.svg @@ -9,7 +9,7 @@ - + @@ -17,7 +17,7 @@ core2 - 88.2188% - 88.2188% + 88.6047% + 88.6047% \ No newline at end of file diff --git a/progress/progress_total.svg b/progress/progress_total.svg index fc4dd50c..f0b50deb 100644 --- a/progress/progress_total.svg +++ b/progress/progress_total.svg @@ -9,7 +9,7 @@ - + @@ -17,7 +17,7 @@ Banjo-Kazooie (us.v10) - 89.2214% - 89.2214% + 89.9076% + 89.9076% \ No newline at end of file diff --git a/src/core1/code_13990.c b/src/core1/code_13990.c index 08e8dd7e..2216920e 100644 --- a/src/core1/code_13990.c +++ b/src/core1/code_13990.c @@ -33,7 +33,32 @@ void mlMtxApply(Mtx *mPtr){ func_80245A7C(D_80282FD0, mPtr); } +#ifndef NONMATCHING #pragma GLOBAL_ASM("asm/nonmatchings/core1/code_13990/func_802514BC.s") +#else +void func_802514BC(Mtx *arg0) { + s32 i, j, k; + f32 tmp; + f32 sp38[4][4]; + f32 (*sp34)[4]; + f32 (*var_s0)[4]; + + + sp34 = reinterpret_cast(f32 *, *D_80282FD0); + var_s0 = reinterpret_cast(f32 *, arg0); + + for(i = 0; i < 4; i++){ + for(j = 0; j < 4; j++){ + tmp = 0.0f; + for(k = 0; k < 4; k++){ + tmp += var_s0[i][k] * sp34[k][j]; + } + sp38[i][j] = tmp; + } + } + func_80253010(sp34, &sp38, sizeof(Mtx)); +} +#endif #pragma GLOBAL_ASM("asm/nonmatchings/core1/code_13990/func_802515D4.s") @@ -57,31 +82,13 @@ void func_80251738(void){ v0[0] = 1.0f; } -#ifndef NONMATCHING -#pragma GLOBAL_ASM("asm/nonmatchings/core1/code_13990/func_80251788.s") -#else f32 *func_80251788(f32 arg0, f32 arg1, f32 arg2){ - f32 (* v0)[4][4] = (f32 *) ++D_80282FD0; - - (*v0)[0][3] = 0.0f; - (*v0)[0][2] = 0.0f; - (*v0)[0][1] = 0.0f; - (*v0)[1][3] = 0.0f; - (*v0)[1][2] = 0.0f; - (*v0)[1][0] = 0.0f; - (*v0)[2][3] = 0.0f; - (*v0)[2][1] = 0.0f; - (*v0)[2][0] = 0.0f; - (*v0)[0][0] = 1.0f; - (*v0)[1][1] = 1.0f; - (*v0)[2][2] = 1.0f; - (*v0)[3][3] = 1.0f; - (*v0)[3][2] = arg2; - (*v0)[3][1] = arg1; - (*v0)[3][0] = arg0; - return &(*v0)[3][3]; + f32 * var_v0 = ++D_80282FD0; + *(var_v0++) = 1.0f; *(var_v0++) = 0.0f; *(var_v0++) = 0.0f; *(var_v0++) = 0.0f; + *(var_v0++) = 0.0f; *(var_v0++) = 1.0f; *(var_v0++) = 0.0f; *(var_v0++) = 0.0f; + *(var_v0++) = 0.0f; *(var_v0++) = 0.0f; *(var_v0++) = 1.0f; *(var_v0++) = 0.0f; + *(var_v0++) = arg0; *(var_v0++) = arg1; *(var_v0++) = arg2; *(var_v0++) = 1.0f; } -#endif #pragma GLOBAL_ASM("asm/nonmatchings/core1/code_13990/func_802517F8.s") @@ -92,7 +99,7 @@ f32 *func_80251788(f32 arg0, f32 arg1, f32 arg2){ //mlMtx void mlMtxIdent(void){ s32 i; - f32 *v0 = D_80282FD0 = D_80282810; + f32 *v0 = D_80282FD0 = &D_80282810; for(i = 0; i<3; i++){ v0[0] = 1.0f; v0[1] = 0.0f; @@ -104,7 +111,13 @@ void mlMtxIdent(void){ v0[0] = 1.0f; } -#pragma GLOBAL_ASM("asm/nonmatchings/core1/code_13990/func_80251B5C.s") +void func_80251B5C(f32 arg0, f32 arg1, f32 arg2){ + f32 * var_v0 = D_80282FD0 = &D_80282810; + *(var_v0++) = 1.0f; *(var_v0++) = 0.0f; *(var_v0++) = 0.0f; *(var_v0++) = 0.0f; + *(var_v0++) = 0.0f; *(var_v0++) = 1.0f; *(var_v0++) = 0.0f; *(var_v0++) = 0.0f; + *(var_v0++) = 0.0f; *(var_v0++) = 0.0f; *(var_v0++) = 1.0f; *(var_v0++) = 0.0f; + *(var_v0++) = arg0; *(var_v0++) = arg1; *(var_v0++) = arg2; *(var_v0++) = 1.0f; +} #pragma GLOBAL_ASM("asm/nonmatchings/core1/code_13990/func_80251BCC.s") @@ -347,62 +360,3 @@ void func_80252FC8(f32 arg0[3]){ mlMtxRotRoll(-arg0[2]); } -#pragma GLOBAL_ASM("asm/nonmatchings/core1/code_13990/func_80253010.s") - -#pragma GLOBAL_ASM("asm/nonmatchings/core1/code_13990/func_80253034.s") - -typedef struct{ - u32 unk0; - u32 unk4; -}struct49s; - -extern struct49s D_803FFE10[]; - -extern u8 D_8000E800; -extern u8 D_8002D500; -extern u32 D_8027BF2C; -extern u32 D_8027BF30; - -void func_80253050( - s32 overlay_id, u32 ram_start, u32 ram_end, u32 rom_start, u32 rom_end, - u32 code_start, u32 code_end, u32 data_start, u32 data_end, u32 bss_start, u32 bss_end -){ - u32 sp34; - u32 sp30; - u32 sp2C; - u32 *tmp; - - osWriteBackDCacheAll(); - osInvalDCache(ram_start, ram_end - ram_start); - osInvalICache(ram_start, ram_end - ram_start); - - if(bss_start){ - osInvalDCache(bss_start, bss_end - bss_start); - } - - rom_start = D_803FFE10[overlay_id].unk0; - rom_end = D_803FFE10[overlay_id].unk4; - - if(overlay_id){ - func_80254008(); - sp34 = &D_8000E800; - } - else{ - sp34 = &D_8002D500; - } - func_802405F0(sp34, rom_start, rom_end - rom_start); - rarezip_uncompress(&sp34, &ram_start); - sp2C = D_8027BF2C; - sp30 = D_8027BF30; - rarezip_uncompress(&sp34, &ram_start); - - if(bss_start){ - bzero(bss_start, bss_end - bss_start); - osWriteBackDCacheAll(); - tmp = (u32*) bss_start; - tmp[0] = sp2C; - tmp[1] = sp30; - tmp[2] = D_8027BF2C; - tmp[3] = D_8027BF30; - } -} diff --git a/src/core1/code_15630.c b/src/core1/code_15630.c new file mode 100644 index 00000000..f75b923d --- /dev/null +++ b/src/core1/code_15630.c @@ -0,0 +1,60 @@ +#include +#include "functions.h" +#include "variables.h" + + +typedef struct{ + u32 unk0; + u32 unk4; +}struct49s; + +extern struct49s D_803FFE10[]; + +extern u8 D_8000E800; +extern u8 D_8002D500; +extern u32 D_8027BF2C; +extern u32 D_8027BF30; + +void func_80253050( + s32 overlay_id, u32 ram_start, u32 ram_end, u32 rom_start, u32 rom_end, + u32 code_start, u32 code_end, u32 data_start, u32 data_end, u32 bss_start, u32 bss_end +){ + u32 sp34; + u32 sp30; + u32 sp2C; + u32 *tmp; + + osWriteBackDCacheAll(); + osInvalDCache(ram_start, ram_end - ram_start); + osInvalICache(ram_start, ram_end - ram_start); + + if(bss_start){ + osInvalDCache(bss_start, bss_end - bss_start); + } + + rom_start = D_803FFE10[overlay_id].unk0; + rom_end = D_803FFE10[overlay_id].unk4; + + if(overlay_id){ + func_80254008(); + sp34 = &D_8000E800; + } + else{ + sp34 = &D_8002D500; + } + func_802405F0(sp34, rom_start, rom_end - rom_start); + rarezip_uncompress(&sp34, &ram_start); + sp2C = D_8027BF2C; + sp30 = D_8027BF30; + rarezip_uncompress(&sp34, &ram_start); + + if(bss_start){ + bzero(bss_start, bss_end - bss_start); + osWriteBackDCacheAll(); + tmp = (u32*) bss_start; + tmp[0] = sp2C; + tmp[1] = sp30; + tmp[2] = D_8027BF2C; + tmp[3] = D_8027BF30; + } +} diff --git a/src/core1/code_22E40.c b/src/core1/code_22E40.c deleted file mode 100644 index 88a722aa..00000000 --- a/src/core1/code_22E40.c +++ /dev/null @@ -1,91 +0,0 @@ -#include -#include "n_libaudio.h" -#include "n_synth.h" -// #include "functions.h" -// #include "variables.h" - -#pragma GLOBAL_ASM("asm/nonmatchings/core1/code_22E40/func_80260860.s") - -#pragma GLOBAL_ASM("asm/nonmatchings/core1/code_22E40/func_802609E0.s") - -#pragma GLOBAL_ASM("asm/nonmatchings/core1/code_22E40/func_80260BD4.s") - -#pragma GLOBAL_ASM("asm/nonmatchings/core1/code_22E40/n_alEnvmixerPull.s") - -#ifdef NONMATCHING -#pragma GLOBAL_ASM("asm/nonmatchings/core1/code_22E40/__postNextSeqEvent.s") -#else -void __postNextSeqEvent(ALSeqPlayer *seqp) -{ - ALEvent evt; - s32 deltaTicks; - ALSeq *seq = seqp->target; - - /* sct 1/5/96 - Do nothing if we're not playing or don't have a target sequence. */ - if ((seqp->state != AL_PLAYING) || (seq == NULL)) - return; - - /* Get the next event time in ticks. */ - /* If false is returned, then there is no next delta (ie. end of sequence reached). */ - if (!__alSeqNextDelta(seq, &deltaTicks)) - return; - - /* Handle loops. */ - if (seqp->loopCount) - { - /* Assume that the loop end falls on a MIDI event. Delta time - will be correct even if we loop */ - if (alSeqGetTicks(seq) + deltaTicks >= seqp->loopEnd->curTicks) - { - alSeqSetLoc(seq, seqp->loopStart); - - if (seqp->loopCount != -1) - seqp->loopCount--; - } - } - - evt.type = AL_SEQ_REF_EVT; - //alEvtqPostEvent(&seqp->evtq, &evt, deltaTicks * seqp->uspt); - alEvtqPostEvent(&seqp->evtq, &evt, deltaTicks * seqp->uspt); -} -#endif - -#pragma GLOBAL_ASM("asm/nonmatchings/core1/code_22E40/__setInstChanState.s") - -#pragma GLOBAL_ASM("asm/nonmatchings/core1/code_22E40/func_80261348.s") - -#pragma GLOBAL_ASM("asm/nonmatchings/core1/code_22E40/__initFromBank.s") - -#pragma GLOBAL_ASM("asm/nonmatchings/core1/code_22E40/func_80261490.s") - -#pragma GLOBAL_ASM("asm/nonmatchings/core1/code_22E40/__vsDelta.s") - -#pragma GLOBAL_ASM("asm/nonmatchings/core1/code_22E40/__vsVol.s") - -#pragma GLOBAL_ASM("asm/nonmatchings/core1/code_22E40/__seqpReleaseVoice.s") - -#pragma GLOBAL_ASM("asm/nonmatchings/core1/code_22E40/__voiceNeedsNoteKill.s") - -#pragma GLOBAL_ASM("asm/nonmatchings/core1/code_22E40/__unmapVoice.s") - -#pragma GLOBAL_ASM("asm/nonmatchings/core1/code_22E40/func_802617A0.s") - -#pragma GLOBAL_ASM("asm/nonmatchings/core1/code_22E40/__vsPan.s") - -#pragma GLOBAL_ASM("asm/nonmatchings/core1/code_22E40/__lookupVoice.s") - -#pragma GLOBAL_ASM("asm/nonmatchings/core1/code_22E40/__mapVoice.s") - -#pragma GLOBAL_ASM("asm/nonmatchings/core1/code_22E40/__lookupSoundQuick.s") - -#pragma GLOBAL_ASM("asm/nonmatchings/core1/code_22E40/func_80261A94.s") - -#pragma GLOBAL_ASM("asm/nonmatchings/core1/code_22E40/func_802623F4.s") - -#pragma GLOBAL_ASM("asm/nonmatchings/core1/code_22E40/func_802623FC.s") - -#pragma GLOBAL_ASM("asm/nonmatchings/core1/code_22E40/__seqpStopOsc.s") - -#pragma GLOBAL_ASM("asm/nonmatchings/core1/code_22E40/__initChanState.s") - -#pragma GLOBAL_ASM("asm/nonmatchings/core1/code_22E40/func_80262BFC.s") diff --git a/src/core1/done/audio/n_seqplayer.c b/src/core1/done/audio/n_seqplayer.c new file mode 100644 index 00000000..5e35705d --- /dev/null +++ b/src/core1/done/audio/n_seqplayer.c @@ -0,0 +1,1221 @@ +#include +#include "n_libaudio.h" +#include "n_synth.h" +#include "file_and_line.h" +#include "assert.h" +// #include "functions.h" +// #include "variables.h" + +#define KILL_TIME 50000 + +void __postNextSeqEvent(ALSeqPlayer *seqp); +ALVoiceState *__mapVoice(ALSeqPlayer *seqp, u8 key, u8 vel, u8 channel); +void __unmapVoice(ALSeqPlayer *seqp, ALVoice *voice) ; +ALVoiceState *__lookupVoice(ALSeqPlayer *seqp, u8 key, u8 channel); +ALSound *__lookupSound(ALSeqPlayer *seqp, u8 key, u8 vel, u8 chan); +ALSound *__lookupSoundQuick(ALSeqPlayer *seqp, u8 key, u8 vel, u8 chan); +s16 __vsVol(N_ALVoiceState *vs, ALSeqPlayer *seqp); +ALMicroTime __vsDelta(ALVoiceState *vs, ALMicroTime t); +ALPan __vsPan(ALVoiceState *vs, ALSeqPlayer *seqp); +void __seqpReleaseVoice(ALSeqPlayer *seqp, ALVoice *voice, ALMicroTime deltaTime); +char __voiceNeedsNoteKill (ALSeqPlayer *seqp, ALVoice *voice, ALMicroTime killTime); +void __initFromBank(ALSeqPlayer *seqp, ALBank *b); +void __setInstChanState(ALSeqPlayer *seqp, ALInstrument *inst, s32 chan); +void func_80261348(ALSeqPlayer *seqp, s32 chan); //__resetPerfChanState +void __initChanState(ALSeqPlayer *seqp); +void __seqpStopOsc(ALSeqPlayer *seqp, ALVoiceState *vs); +void func_80263850(ALSeq *, ALEvent *); + + +static ALMicroTime __seqpVoiceHandler(void *node); +static void func_80261A94(ALSeqPlayer *seqp, ALEvent *event); //__handleMIDIMsg +static void func_802617A0(ALSeqPlayer *seqp, ALEvent *event); //__handleMetaMsg +static void __handleNextSeqEvent(ALSeqPlayer *seqp); +static void __setUsptFromTempo(ALSeqPlayer *seqp, f32 tempo); /* sct 1/8/96 */ + +/* + * Sequence Player public functions + */ +void n_alSeqpNew(N_ALSeqPlayer *seqp, ALSeqpConfig *c) +{ + s32 i; + ALEventListItem *items; + ALVoiceState *vs; + ALVoiceState *voices; + ALHeap *hp = c->heap; + + /* + * initialize member variables + */ + seqp->bank = 0; + seqp->target = NULL; + seqp->drvr = &n_syn->head; + seqp->chanMask = 0xff; + seqp->uspt = 488; + seqp->nextDelta = 0; + seqp->state = AL_STOPPED; + seqp->vol = 0x7FFF; /* full volume */ + seqp->debugFlags = c->debugFlags; + seqp->frameTime = AL_USEC_PER_FRAME; /* should get this from driver */ + seqp->curTime = 0; + seqp->initOsc = c->initOsc; + seqp->updateOsc = c->updateOsc; + seqp->stopOsc = c->stopOsc; + seqp->loopStart = 0; + seqp->loopEnd = 0; + seqp->loopCount = 0; /* -1 = loop forever, 0 = no loop */ + + seqp->nextEvent.type = AL_SEQP_API_EVT; /* start the voice handler "spinning" */ + + /* + * init the channel state + */ + seqp->maxChannels = c->maxChannels; + seqp->chanState = alHeapAlloc(hp, c->maxChannels, sizeof(ALChanState) ); + __initChanState(seqp); /* sct 11/6/95 */ + + /* + * init the voice state array + */ + voices = alHeapAlloc(hp, c->maxVoices, sizeof(ALVoiceState)); + seqp->vFreeList = 0; + for (i = 0; i < c->maxVoices; i++) { + vs = &voices[i]; + vs->next = seqp->vFreeList; + seqp->vFreeList = vs; + } + + seqp->vAllocHead = 0; + seqp->vAllocTail = 0; + + /* + * init the event queue + */ + items = alHeapAlloc(hp, c->maxEvents, sizeof(ALEventListItem)); + alEvtqNew(&seqp->evtq, items, c->maxEvents); + + /* + * add ourselves to the driver + */ + seqp->node.next = NULL; + seqp->node.handler = __seqpVoiceHandler; + seqp->node.clientData = seqp; + n_alSynAddSeqPlayer(&seqp->node); +} + +/************************************************************* + * private routines or driver callback routines + *************************************************************/ +ALMicroTime __seqpVoiceHandler(void *node) +{ + ALSeqPlayer *seqp = (ALSeqPlayer *) node; + ALEvent evt; + ALVoice *voice; + ALMicroTime delta; + ALVoiceState *vs; + void *oscState; + f32 oscValue; + u8 chan; + + do { + + switch (seqp->nextEvent.type) { + + case (AL_SEQ_REF_EVT): + __handleNextSeqEvent(seqp); + break; + + case (AL_SEQP_API_EVT): + evt.type = AL_SEQP_API_EVT; + alEvtqPostEvent(&seqp->evtq, (ALEvent *)&evt, seqp->frameTime); + break; + + case (AL_NOTE_END_EVT): + voice = seqp->nextEvent.msg.note.voice; + n_alSynStopVoice(voice); + n_alSynFreeVoice(voice); + vs = (ALVoiceState *)voice->clientPrivate; + if(vs->flags) + __seqpStopOsc((ALSeqPlayer*)seqp,vs); + __unmapVoice(seqp, voice); + break; + + case (AL_SEQP_ENV_EVT): + voice = seqp->nextEvent.msg.vol.voice; + vs = (ALVoiceState *)voice->clientPrivate; + + if (vs->envPhase == AL_PHASE_ATTACK) + vs->envPhase = AL_PHASE_DECAY; + + delta = seqp->nextEvent.msg.vol.delta; + vs->envGain = seqp->nextEvent.msg.vol.vol; + vs->envEndTime = seqp->curTime + delta; + n_alSynSetVol(voice, __vsVol(vs, seqp), delta); + break; + + case (AL_TREM_OSC_EVT): + vs = seqp->nextEvent.msg.osc.vs; + oscState = seqp->nextEvent.msg.osc.oscState; + delta = (*seqp->updateOsc)(oscState,&oscValue); + vs->tremelo = (u8)oscValue; + n_alSynSetVol(&vs->voice, __vsVol(vs,seqp), + __vsDelta(vs,seqp->curTime)); + evt.type = AL_TREM_OSC_EVT; + evt.msg.osc.vs = vs; + evt.msg.osc.oscState = oscState; + alEvtqPostEvent(&seqp->evtq, &evt, delta); + break; + + case (AL_VIB_OSC_EVT): + vs = seqp->nextEvent.msg.osc.vs; + oscState = seqp->nextEvent.msg.osc.oscState; + chan = seqp->nextEvent.msg.osc.chan; + delta = (*seqp->updateOsc)(oscState,&oscValue); + vs->vibrato = oscValue; + n_alSynSetPitch(&vs->voice, vs->pitch * vs->vibrato + * seqp->chanState[chan].pitchBend); + evt.type = AL_VIB_OSC_EVT; + evt.msg.osc.vs = vs; + evt.msg.osc.oscState = oscState; + evt.msg.osc.chan = chan; + alEvtqPostEvent(&seqp->evtq, &evt, delta); + break; + + case (AL_SEQP_MIDI_EVT): + func_80261A94(seqp, &seqp->nextEvent); + break; + + case (AL_SEQP_META_EVT): + func_802617A0(seqp, &seqp->nextEvent); + break; + + case (AL_SEQP_PLAY_EVT): + if (seqp->state != AL_PLAYING) + { + seqp->state = AL_PLAYING; + __postNextSeqEvent(seqp); /* seqp must be AL_PLAYING before we call this routine. */ + } + break; + + case (AL_SEQP_STOP_EVT): + if ( seqp->state == AL_STOPPING ) + { + for (vs = seqp->vAllocHead; vs != 0; vs = seqp->vAllocHead) + { + n_alSynStopVoice(&vs->voice); + n_alSynFreeVoice(&vs->voice); + if(vs->flags) + __seqpStopOsc((ALSeqPlayer*)seqp,vs); + __unmapVoice((ALSeqPlayer*)seqp, &vs->voice); + } + + seqp->curTime = 0; + seqp->state = AL_STOPPED; + + /* alEvtqFlush(&seqp->evtq); - Don't flush event + queue anymore. */ + /* sct 1/3/96 - Don't overwrite nextEvent with + AL_SEQP_API_EVT or set nextDelta to + AL_USEC_PER_FRAME since we're not stopping event + processing. */ + /* sct 1/3/96 - Don't return here since we keep + processing events as usual. */ + } + break; + + case (AL_SEQP_STOPPING_EVT): + if (seqp->state == AL_PLAYING) + { + /* + * sct 12/29/95 - Remove events associated with the + * stopping sequence. Note that flushing + * AL_SEQP_MIDI_EVTs may flush events that were + * posted after the call to alSeqpStop, so the + * application must queue these events either when + * the player is fully stopped, or when it is + * playing. + */ + alEvtqFlushType(&seqp->evtq, AL_SEQ_REF_EVT); + alEvtqFlushType(&seqp->evtq, AL_SEQP_MIDI_EVT); + + /* + * sct 1/3/96 - Check to see which voices need to be + * killed and release them. Unkilled voices should + * have note end events occurring prior to + * KILL_TIME. + */ + for (vs = seqp->vAllocHead; vs != 0; vs = vs->next) + { + if (__voiceNeedsNoteKill (seqp, &vs->voice, KILL_TIME)) + __seqpReleaseVoice(seqp, &vs->voice, KILL_TIME); + } + + seqp->state = AL_STOPPING; + evt.type = AL_SEQP_STOP_EVT; + alEvtqPostEvent(&seqp->evtq, &evt, AL_EVTQ_END); + } + break; + + case (AL_SEQP_VOL_EVT): + seqp->vol = seqp->nextEvent.msg.spvol.vol; + for (vs = seqp->vAllocHead; vs != 0; vs = vs->next) { + n_alSynSetVol(&vs->voice, __vsVol(vs, seqp), __vsDelta(vs, seqp->curTime)); + } + break; + + case (AL_SEQP_LOOP_EVT): + seqp->loopStart = seqp->nextEvent.msg.loop.start; + seqp->loopEnd = seqp->nextEvent.msg.loop.end; + seqp->loopCount = seqp->nextEvent.msg.loop.count; + break; + + case (AL_SEQP_PRIORITY_EVT): + chan = seqp->nextEvent.msg.sppriority.chan; + seqp->chanState[chan].priority = seqp->nextEvent.msg.sppriority.priority; + break; + + case (AL_SEQP_SEQ_EVT): + matching_assert(seqp->state != AL_PLAYING, n_seqplayer.c, 0x11A); /* Must be done playing to change sequences. */ + + seqp->target = seqp->nextEvent.msg.spseq.seq; + __setUsptFromTempo (seqp, 500000.0); + if (seqp->bank) + __initFromBank(seqp, seqp->bank); + break; + + case (AL_SEQP_BANK_EVT): + matching_assert(seqp->state == AL_STOPPED, n_seqplayer.c, 0x123); /* Must be fully stopped to change banks. */ + + seqp->bank = seqp->nextEvent.msg.spbank.bank; + __initFromBank(seqp, seqp->bank); + break; + + /* sct 11/6/95 - these events should now be handled by __handleNextSeqEvent */ + case (AL_SEQ_END_EVT): + case (AL_TEMPO_EVT): + case (AL_SEQ_MIDI_EVT): + matching_assert(FALSE, n_seqplayer.c, 0x12d); + break; + } + + seqp->nextDelta = alEvtqNextEvent (&seqp->evtq, &seqp->nextEvent); + + } while (seqp->nextDelta == 0); + + /* + * assume that next callback won't be more than half an hour away + */ + seqp->curTime += seqp->nextDelta; /* Update the player's current time. */ + return seqp->nextDelta; +} + +/* + Call this routine to handle the next event in the sequence. + Assumes that the next sequence event is scheduled to be processed + immediately since it does not check the event's tick time. + sct 11/7/95 +*/ +static void +__handleNextSeqEvent(ALSeqPlayer *seqp) +{ + ALEvent evt; + + /* sct 1/5/96 - Do nothing if we don't have a target sequence. */ + if (seqp->target == NULL) + return; + + func_80263850(seqp->target, &evt); + + switch (evt.type) + { + case AL_SEQ_MIDI_EVT: + func_80261A94(seqp, &evt); + __postNextSeqEvent(seqp); + break; + + case AL_TEMPO_EVT: + func_802617A0(seqp, &evt); + __postNextSeqEvent(seqp); + break; + + case AL_SEQ_END_EVT: + seqp->state = AL_STOPPING; + evt.type = AL_SEQP_STOP_EVT; + alEvtqPostEvent(&seqp->evtq, &evt, AL_EVTQ_END); + break; + + default: + matching_assert(FALSE, n_seqplayer.c, 0x162); /* Sequence event type not supported. */ + } +} + + +void func_80261A94(ALSeqPlayer *seqp, ALEvent *event) +{ + ALVoice *voice; + ALVoiceState *vs; + s32 status; + u8 chan; + u8 key; + u8 vel; + u8 byte1; + u8 byte2; + ALMIDIEvent *midi = &event->msg.midi; + s16 vol; + ALEvent evt; + ALMicroTime deltaTime; + ALVoiceState *vstate; + ALPan pan; + ALFxRef fxref; + + /* sct 12/15/95 - Fixed assert to also allow seqp midi event types. */ + matching_assert(event->type == AL_SEQ_MIDI_EVT || event->type == AL_SEQP_MIDI_EVT, n_seqplayer.c, 0x17b); + + status = midi->status & AL_MIDI_StatusMask; + chan = midi->status & AL_MIDI_ChannelMask; + byte1 = key = midi->byte1; + byte2 = vel = midi->byte2; + + switch (status) { + + case (AL_MIDI_NoteOn): + + if (vel != 0) { /* a real note on */ + ALVoiceConfig config; + ALSound *sound; + s16 cents; + f32 pitch,oscValue; + u8 fxmix; + void *oscState; + ALInstrument *inst; + + /* If we're not playing, don't process note ons. */ + if (seqp->state != AL_PLAYING) + break; + + sound = __lookupSoundQuick(seqp, key, vel, chan); + ALFlagFailIf(!sound, seqp->debugFlags & NO_SOUND_ERR_MASK, + ERR_ALSEQP_NO_SOUND); + + config.priority = seqp->chanState[chan].priority; + config.fxBus = 0; + config.unityPitch = 0; + + vstate = __mapVoice(seqp, key, vel, chan); + ALFlagFailIf(!vstate, seqp->debugFlags & NO_VOICE_ERR_MASK, + ERR_ALSEQP_NO_VOICE ); + + voice = &vstate->voice; + + n_alSynAllocVoice(voice, &config); + + /* + * set up the voice state structure + */ + vstate->sound = sound; + vstate->envPhase = AL_PHASE_ATTACK; + if (seqp->chanState[chan].sustain > AL_SUSTAIN) + vstate->phase = AL_PHASE_SUSTAIN; + else + vstate->phase = AL_PHASE_NOTEON; + + cents = (key - sound->keyMap->keyBase) * 100 + + sound->keyMap->detune; + + vstate->pitch = alCents2Ratio(cents); + vstate->envGain = sound->envelope->attackVolume; + vstate->envEndTime = seqp->curTime + + sound->envelope->attackTime; + + /* + * setup tremelo and vibrato if active + */ + vstate->flags = 0; + inst = seqp->chanState[chan].instrument; + + oscValue = (f32)AL_VOL_FULL; /* set this as a default */ + + if(inst->tremType) + { + if(seqp->initOsc) + { + deltaTime = (*seqp->initOsc)(&oscState,&oscValue, + inst->tremType, + inst->tremRate, + inst->tremDepth, + inst->tremDelay); + + if(deltaTime) /* if deltaTime = zero, don't run osc */ + { + evt.type = AL_TREM_OSC_EVT; + evt.msg.osc.vs = vstate; + evt.msg.osc.oscState = oscState; + alEvtqPostEvent(&seqp->evtq, &evt, deltaTime); + vstate->flags |= 0x01; /* set tremelo flag bit */ + } + } + } + /* will default if not changed by initOsc */ + vstate->tremelo = (u8)oscValue; + + oscValue = 1.0f; /* set this as a default */ + if(inst->vibType) + { + if(seqp->initOsc) + { + deltaTime = (*seqp->initOsc)(&oscState,&oscValue, + inst->vibType, + inst->vibRate, + inst->vibDepth, + inst->vibDelay); + + if(deltaTime) /* if deltaTime = zero,don't run osc. */ + { + evt.type = AL_VIB_OSC_EVT; + evt.msg.osc.vs = vstate; + evt.msg.osc.oscState = oscState; + evt.msg.osc.chan = chan; + alEvtqPostEvent(&seqp->evtq, &evt, deltaTime); + vstate->flags |= 0x02; /* set the vibrato flag bit */ + } + } + } + /* will default if not changed by initOsc */ + vstate->vibrato = oscValue; + + /* + * calculate the note on parameters + */ + pitch = vstate->pitch * seqp->chanState[chan].pitchBend * + vstate->vibrato; + fxmix = seqp->chanState[chan].fxmix; + pan = __vsPan(vstate, seqp); + vol = __vsVol(vstate, seqp); + deltaTime = sound->envelope->attackTime; + + n_alSynStartVoiceParams(voice, sound->wavetable, + pitch, vol, pan, fxmix, deltaTime); + /* + * set up callbacks for envelope + */ + evt.type = AL_SEQP_ENV_EVT; + evt.msg.vol.voice = voice; + evt.msg.vol.vol = sound->envelope->decayVolume; + evt.msg.vol.delta = sound->envelope->decayTime; + deltaTime = sound->envelope->attackTime; + + alEvtqPostEvent(&seqp->evtq, &evt, deltaTime); + + break; + } + + /* + * NOTE: intentional fall-through for note on with zero + * velocity + */ + + case (AL_MIDI_NoteOff): + vstate = __lookupVoice(seqp, key, chan); + ALFlagFailIf(!vstate, (seqp->debugFlags & NOTE_OFF_ERR_MASK), + ERR_ALSEQP_OFF_VOICE ); + + if (vstate->phase == AL_PHASE_SUSTAIN) + { + rmonPrintf("TRACE: '%s' {Line %d}\n", FILE(n_seqplayer.c), LINE(0x211)); + vstate->phase = AL_PHASE_SUSTREL; + } else { + vstate->phase = AL_PHASE_RELEASE; + rmonPrintf("TRACE: '%s' {Line %d}\n", FILE(n_seqplayer.c), LINE(0x214)); + __seqpReleaseVoice(seqp, &vstate->voice, + vstate->sound->envelope->releaseTime); + } + + break; + + case (AL_MIDI_PolyKeyPressure): + /* + * Aftertouch per key (hardwired to volume). Note that + * aftertouch affects only notes that are already + * sounding. + */ + vstate = __lookupVoice(seqp, key, chan); + ALFailIf(!vstate, ERR_ALSEQP_POLY_VOICE ); + + vstate->velocity = byte2; + n_alSynSetVol(&vstate->voice, __vsVol(vstate, seqp), + __vsDelta(vstate, seqp->curTime)); + break; + + case (AL_MIDI_ChannelPressure): + /* + * Aftertouch per channel (hardwired to volume). Note that + * aftertouch affects only notes that are already + * sounding. + */ + for (vs = seqp->vAllocHead; vs != 0; vs = vs->next) { + if (vs->channel == chan) { + vs->velocity = byte1; + n_alSynSetVol(&vs->voice, __vsVol(vs, seqp), + __vsDelta(vs, seqp->curTime)); + } + } + break; + + case (AL_MIDI_ControlChange): + + switch (byte1) { + + case (AL_MIDI_PAN_CTRL): + seqp->chanState[chan].pan = byte2; + for (vs = seqp->vAllocHead; vs != 0; vs = vs->next) { + if (vs->channel == chan) { + pan = __vsPan(vs, seqp); + n_alSynSetPan(&vs->voice, pan); + } + } + break; + + + case (AL_MIDI_VOLUME_CTRL): + seqp->chanState[chan].vol = byte2; + for (vs = seqp->vAllocHead; vs != 0; vs = vs->next) { + if ((vs->channel == chan) && + (vs->envPhase != AL_PHASE_RELEASE)) + { + vol = __vsVol(vs, seqp); + n_alSynSetVol(&vs->voice, vol, + __vsDelta(vs, seqp->curTime)); + } + } + break; + + case (0x7D): + seqp->chanState[chan].unkA = byte2; + for (vs = seqp->vAllocHead; vs != 0; vs = vs->next) { + if ((vs->channel == chan) && + (vs->envPhase != AL_PHASE_RELEASE)) + { + vol = __vsVol(vs, seqp); + n_alSynSetVol(&vs->voice, vol, + __vsDelta(vs, seqp->curTime)); + } + } + break; + + case (AL_MIDI_PRIORITY_CTRL): + /* leave current voices where they are */ + seqp->chanState[chan].priority = byte2; + break; + case (AL_MIDI_SUSTAIN_CTRL): + seqp->chanState[chan].sustain = byte2; + for (vs = seqp->vAllocHead; vs != 0; vs = vs->next) { + if ((vs->channel == chan) && + (vs->phase != AL_PHASE_RELEASE)) { + if ( byte2 > AL_SUSTAIN ) { + /* + * sustain pedal down + */ + if (vs->phase == AL_PHASE_NOTEON) + vs->phase = AL_PHASE_SUSTAIN; + } else { + /* + * sustain pedal up + */ + if (vs->phase == AL_PHASE_SUSTAIN) + vs->phase = AL_PHASE_NOTEON; + else if(vs->phase == AL_PHASE_SUSTREL) { + vs->phase = AL_PHASE_RELEASE; + __seqpReleaseVoice(seqp, &vs->voice, + vs->sound->envelope->releaseTime); + } + } + } + } + break; + + case (AL_MIDI_FX1_CTRL): + seqp->chanState[chan].fxmix = byte2; + for (vs = seqp->vAllocHead; vs != 0; vs = vs->next) { + if (vs->channel == chan) { + n_alSynSetFXMix(&vs->voice, byte2); + } + } + break; + + case (AL_MIDI_FX_CTRL_0): + case (AL_MIDI_FX_CTRL_1): + case (AL_MIDI_FX_CTRL_2): + case (AL_MIDI_FX_CTRL_3): + case (AL_MIDI_FX_CTRL_4): + case (AL_MIDI_FX_CTRL_5): + case (AL_MIDI_FX_CTRL_6): + case (AL_MIDI_FX_CTRL_7): +#if 0 /* fx control not implemented */ + fxref = alSynGetFXRef(seqp->drvr, 0, 0); + if (fxref) + alSynSetFXParam(seqp->drvr, fxref, (s16)byte1, (void *)byte2); + break; +#endif + case (AL_MIDI_FX3_CTRL): + default: + break; + + } + break; + + case (AL_MIDI_ProgramChange): + /* sct 1/16/96 - We must have a valid bank in order to process the program change. */ + matching_assert(seqp->bank != NULL, n_seqplayer.c, 0x29c); + + + if (key < seqp->bank->instCount) { + ALInstrument *inst = seqp->bank->instArray[key]; + __setInstChanState(seqp, inst, chan); /* sct 11/6/95 */ + } +#ifdef _DEBUG + else + __osError(ERR_ALSEQPINVALIDPROG, 2, key, seqp->bank->instCount); +#endif + break; + + case (AL_MIDI_PitchBendChange): + { + s32 bendVal; + f32 bendRatio; + s32 cents; + + /* + * get 14-bit unsigned midi value + */ + bendVal = ( (byte2 << 7) + byte1) - 8192; + + /* + * calculate pitch bend in cents + */ + cents = (seqp->chanState[chan].bendRange * bendVal)/8192; + + /* + * calculate the corresponding ratio + */ + bendRatio = alCents2Ratio(cents); + seqp->chanState[chan].pitchBend = bendRatio; + + for (vs = seqp->vAllocHead; vs != 0; vs = vs->next) { + if (vs->channel == chan) { + n_alSynSetPitch(&vs->voice, + vs->pitch * bendRatio * vs->vibrato); + } + } + } + break; + + default: +#ifdef _DEBUG + __osError(ERR_ALSEQPUNKNOWNMIDI, 1, status); +#endif + break; + } +} + +void func_802617A0(ALSeqPlayer *seqp, ALEvent *event) +{ + ALTempoEvent *tevt = &event->msg.tempo; + ALEvent evt; + s32 tempo; + + if (event->msg.tempo.status == AL_MIDI_Meta) + { + if (event->msg.tempo.type == AL_MIDI_META_TEMPO) + { + tempo = + (tevt->byte1 << 16) | + (tevt->byte2 << 8) | + (tevt->byte3 << 0); + __setUsptFromTempo (seqp, (f32)tempo); /* sct 1/8/96 */ + } + } +} + +ALVoiceState *__mapVoice(ALSeqPlayer *seqp, u8 key, u8 vel, u8 channel) +{ + ALVoiceState *vs = seqp->vFreeList; + + if (vs) { + + seqp->vFreeList = vs->next; + + vs->next = 0; + + if (!seqp->vAllocHead) + seqp->vAllocHead = vs; + else + seqp->vAllocTail->next = vs; + + seqp->vAllocTail = vs; + + vs->channel = channel; + vs->key = key; + vs->velocity = vel; + vs->voice.clientPrivate = vs; + } + + return vs; +} + +void __unmapVoice(ALSeqPlayer *seqp, ALVoice *voice) +{ + ALVoiceState *prev = 0; + ALVoiceState *vs; + + /* + * we could use doubly linked lists here and save some code and + * execution time, but time spent here in negligible, so it won't + * make much difference. + */ + for (vs = seqp->vAllocHead; vs != 0; vs = vs->next) { + if (&vs->voice == voice) { + + if (prev) + prev->next = vs->next; + else + seqp->vAllocHead = vs->next; + + if (vs == seqp->vAllocTail) { + seqp->vAllocTail = prev; + } + + vs->next = seqp->vFreeList; + seqp->vFreeList = vs; + return; + + } + prev = vs; + } +#ifdef _DEBUG + __osError(ERR_ALSEQPUNMAP, 1, voice); +#endif +} + +ALVoiceState *__lookupVoice(ALSeqPlayer *seqp, u8 key, u8 channel) +{ + ALVoiceState *vs; + + for (vs = seqp->vAllocHead; vs != 0; vs = vs->next) { + if ((vs->key == key) && (vs->channel == channel) && + (vs->phase != AL_PHASE_RELEASE) && (vs->phase != AL_PHASE_SUSTREL)) + return vs; + } + + return 0; +} + +#if 0 +ALSound *__lookupSound(ALSeqPlayer *seqp, u8 key, u8 vel, u8 chan) +{ + s32 i; + ALInstrument *inst = seqp->chanState[chan].instrument; + ALSound *snd = 0; + + for (i = 0; i < inst->soundCount; i++) { + ALSound *sound = inst->soundArray[i]; + ALKeyMap *keymap = sound->keyMap; + + if ((key >= keymap->keyMin) && (key <= keymap->keyMax) && + (vel >= keymap->velocityMin) && (vel <= keymap->velocityMax)) { + snd = sound; + break; + } + } + return snd; +} +#endif + +ALSound *__lookupSoundQuick(ALSeqPlayer *seqp, u8 key, u8 vel, u8 chan) +{ + ALInstrument *inst = seqp->chanState[chan].instrument; + s32 l = 1; + s32 r = inst->soundCount; + s32 i; + ALKeyMap *keymap; + + matching_assert(inst != NULL, n_seqplayer.c, 0x3DE); /* sct 10/31/95 - If inst is NULL, then the seqp probably wasn't setup correctly. */ + + while (r >= l) { + i = (l+r)/2; + + keymap = inst->soundArray[i-1]->keyMap; + + if ((key >= keymap->keyMin) && (key <= keymap->keyMax) && + (vel >= keymap->velocityMin) && (vel <= keymap->velocityMax)) { + return inst->soundArray[i-1]; + } else if ((key < keymap->keyMin) || + ((vel < keymap->velocityMin) && (key <= keymap->keyMax))) { + r = i - 1; + } else { + l = i + 1; + } + } + + return 0; +} + + +/* + * __vsVol calculates the target volume for the voice based on the + * note on velocity, envelope, sampleVolume and controller. + */ +// s16 __vsVol(ALVoiceState *vs, ALSeqPlayer *seqp) +// { + +// u32 t1,t2; + +// t1 = (vs->tremelo*vs->velocity*vs->envGain) >> 6; +// t2 = (vs->sound->sampleVolume*seqp->vol* +// seqp->chanState[vs->channel].vol) >> 14; + +// t1 *= t2; +// t1 >>= 15; + +// return( (s16)t1 ); + +// } +// s16 __vsVol(ALVoiceState *vs, ALSeqPlayer *seqp) { +// ALChanState *temp_a2; + +// temp_a2 = &seqp->chanState[vs->channel]; +// return (s16) ((u32) (((s32) (temp_a2->unk9 * vs->tremelo * vs->velocity * vs->envGain) >> 0xD) * ((s32) (temp_a2->vol * vs->sound->sampleVolume * seqp->vol) >> 0xE)) >> 0xF); +// } + +s16 __vsVol(N_ALVoiceState *vs, ALSeqPlayer *seqp) +{ + u32 t1, t2; + ALChanState *temp_a2; + t1 = (vs->tremelo*vs->velocity*vs->envGain*seqp->chanState[vs->channel].unkA) >> 13; + t2 = (vs->sound->sampleVolume*seqp->vol*seqp->chanState[vs->channel].vol) >> 14; + + t1 *= t2; + t1 >>= 15; + return ((s16)t1); +} + +ALMicroTime __vsDelta(ALVoiceState *vs, ALMicroTime t) +{ + /* + * If we are interrupting a previously set envelope segment, we + * need to recalculate the segment end time given the current + * time. Note: this routine assumes that the voice is currently + * playing. + */ + + s32 delta = vs->envEndTime - t; + + if (delta >= 0) { + return delta; + } else { + return AL_GAIN_CHANGE_TIME; + } +} + +ALPan __vsPan(ALVoiceState *vs, ALSeqPlayer *seqp) +{ + s32 tmp; + + tmp = seqp->chanState[vs->channel].pan - AL_PAN_CENTER + + vs->sound->samplePan; + tmp = MAX(tmp, AL_PAN_LEFT); + tmp = MIN(tmp, AL_PAN_RIGHT); + + return (ALPan) tmp; +} + +#ifdef IMPLEMENTED + +s32 seqpGetVoices(SEQP *seqp); +s32 seqpSetVoices(SEQP *seqp, s32 numvoices); + +u16 seqpGetChannelMask(SEQP *seqp); +s32 seqpSetChannelMask(SEQP *seqp, u16 bitmask); + +#endif + +void __seqpReleaseVoice(ALSeqPlayer *seqp, ALVoice *voice, + ALMicroTime deltaTime) +{ + ALEvent evt; + ALVoiceState *vs = (ALVoiceState *)voice->clientPrivate; + + /* + * if in attack phase, remove all pending volume + * events for this voice from the queue + */ + + if (vs->envPhase == AL_PHASE_ATTACK) { + ALLink *thisNode; + ALLink *nextNode; + ALEventListItem *thisItem, *nextItem; + + thisNode = seqp->evtq.allocList.next; + while( thisNode != 0 ) { + nextNode = thisNode->next; + thisItem = (ALEventListItem *)thisNode; + nextItem = (ALEventListItem *)nextNode; + if (thisItem->evt.type == AL_SEQP_ENV_EVT) { + if(thisItem->evt.msg.vol.voice == voice) { + if( nextItem ) + nextItem->delta += thisItem->delta; + alUnlink(thisNode); + alLink(thisNode, &seqp->evtq.freeList); + } + } + thisNode = nextNode; + } + } + + vs->velocity = 0; + vs->envPhase = AL_PHASE_RELEASE; + vs->envGain = 0; + vs->envEndTime = seqp->curTime + deltaTime; + + n_alSynSetPriority(voice, 0); /* make candidate for stealing */ + n_alSynSetVol(voice, 0, deltaTime); + evt.type = AL_NOTE_END_EVT; + evt.msg.note.voice = voice; + deltaTime += 0x7D00; + alEvtqPostEvent(&seqp->evtq, &evt, deltaTime); +} + + + +/* + This special purpose routine is called only when processing + a stopping event in order to properly kill all active voices. + + The routine searches through the seqp's event queue for an + AL_NOTE_END_EVT for the given voice. If the event's execution + time is greater than kill time, it removes the event from the + event queue and returns true that it needs to kill the voice. + Otherwise, if the event's time is less than the kill time, it + returns false that the voice needs to be killed. + sct 1/3/96 +*/ + +#define VOICENEEDSNOTEKILL_DEBUG _DEBUG_INTERNAL&&0 /* For debugging voiceNeedsNoteKill routine. */ + +char __voiceNeedsNoteKill (ALSeqPlayer *seqp, ALVoice *voice, ALMicroTime killTime) +{ + ALLink *thisNode; + ALLink *nextNode; + ALEventListItem *thisItem; + ALMicroTime itemTime = 0; + char needsNoteKill = TRUE; + +#if VOICENEEDSNOTEKILL_DEBUG + alEvtqPrintAllocEvts (&seqp->evtq); +#endif + + thisNode = seqp->evtq.allocList.next; + while (thisNode != 0) + { + nextNode = thisNode->next; + thisItem = (ALEventListItem *)thisNode; + itemTime += thisItem->delta; + + if (thisItem->evt.type == AL_NOTE_END_EVT) + { + if (thisItem->evt.msg.note.voice == voice) + { + if (itemTime > killTime) + { + if ((ALEventListItem *)nextNode) + ((ALEventListItem *)nextNode)->delta += thisItem->delta; + alUnlink(thisNode); + alLink(thisNode, &seqp->evtq.freeList); + } + else + needsNoteKill = FALSE; + break; + } + } + thisNode = nextNode; + } + +#if VOICENEEDSNOTEKILL_DEBUG + if (thisNode) + osSyncPrintf("vox 0x%0x: end time %d kill time %d\n\n", voice, itemTime, killTime); + else + osSyncPrintf("vox 0x%0x: not found\n\n", voice); + + alEvtqPrintAllocEvts (&seqp->evtq); +#endif + + return needsNoteKill; +} + + + + +void __initFromBank(ALSeqPlayer *seqp, ALBank *b) +{ + /* + * init the chanState with the default instrument + */ + s32 i; + ALInstrument *inst = 0; + + /* set to the first available instrument. */ + for(i = 0; !inst ; i++) + inst = b->instArray[i]; + + /* sct 11/6/95 - Setup the channel state for the given instrument. */ + /* There is some wasted effort here since both calls the same state vars */ + /* but it's safer. */ + for (i = 0; i < seqp->maxChannels; i++) { + func_80261348(seqp, i); + __setInstChanState(seqp, inst, i); + } + + if (b->percussion) { + func_80261348(seqp, i); + __setInstChanState(seqp, b->percussion, 9); + } +} + + +/* + sct 11/6/95 - Call this whenever a new instrument gets assigned to a channel + such as when changing banks or in response to a MIDI program change event. + Currently also gets called when changing sequences. +*/ + +void __setInstChanState(ALSeqPlayer *seqp, ALInstrument *inst, s32 chan) +{ + seqp->chanState[chan].instrument = inst; + seqp->chanState[chan].pan = inst->pan; + seqp->chanState[chan].vol = inst->volume; + seqp->chanState[chan].priority = inst->priority; + seqp->chanState[chan].bendRange = inst->bendRange; +} + + +/* + sct 11/6/95 -- Call this whenever a new sequence is to be played or when + initializing a sequence player. +*/ + +void func_80261348(ALSeqPlayer *seqp, s32 chan) +{ + seqp->chanState[chan].fxId = AL_FX_NONE; + seqp->chanState[chan].fxmix = AL_DEFAULT_FXMIX; + seqp->chanState[chan].pan = AL_PAN_CENTER; + seqp->chanState[chan].vol = AL_VOL_FULL; + seqp->chanState[chan].unkA = AL_VOL_FULL; + seqp->chanState[chan].priority = AL_DEFAULT_PRIORITY; + seqp->chanState[chan].sustain = 0; + seqp->chanState[chan].bendRange = 200; + seqp->chanState[chan].pitchBend = 1.0f; +} + + +/* + sct 11/6/95 - Called only when creating a new sequence player. +*/ +void __initChanState(ALSeqPlayer *seqp) +{ + int i; + + for (i = 0; i < seqp->maxChannels; i++) + { + seqp->chanState[i].instrument = 0; + func_80261348 (seqp, i); + } +} + + +void __seqpStopOsc(ALSeqPlayer *seqp, ALVoiceState *vs) +{ + ALEventListItem *thisNode,*nextNode; + s16 evtType; + + thisNode = (ALEventListItem*)seqp->evtq.allocList.next; + while(thisNode) + { + nextNode = (ALEventListItem*)thisNode->node.next; + evtType = thisNode->evt.type; + if(evtType == AL_TREM_OSC_EVT || evtType == AL_VIB_OSC_EVT) + { + if(thisNode->evt.msg.osc.vs == vs) + { + (*seqp->stopOsc)(thisNode->evt.msg.osc.oscState); + alUnlink((ALLink*)thisNode); + if(nextNode) + nextNode->delta += thisNode->delta; + alLink((ALLink*)thisNode, &seqp->evtq.freeList); + if(evtType == AL_TREM_OSC_EVT) + vs->flags = vs->flags & 0xFE; + else /* must be a AL_VIB_OSC_EVT */ + vs->flags = vs->flags & 0xFD; + if(!vs->flags) + return; /* there should be no more events */ + } + } + + thisNode = nextNode; + } +} + + + +/* + This routine safely calculates the sequence player's + uspt value based on the given tempo. It does this safely + by making sure that the player has a target sequence and + therefore a qnpt value which is needed for the calculation. +*/ +static void __setUsptFromTempo (ALSeqPlayer *seqp, f32 tempo) +{ + if (seqp->target) + seqp->uspt = (s32)((f32)tempo * seqp->target->qnpt); + else + seqp->uspt = 488; /* This is the initial value set by alSeqpNew. */ +} + +/* + Calculates the delta time in ticks until the next sequence + event taking into account loop points, and posts a + sequence reference event with the time in usecs. + Does nothing if the sequence player is not playing or there + is no target sequence. + sct 11/7/95 +*/ +void __postNextSeqEvent(ALSeqPlayer *seqp) +{ + ALEvent evt; + s32 deltaTicks; + ALSeq *seq = seqp->target; + + /* sct 1/5/96 - Do nothing if we're not playing or don't have a target sequence. */ + if ((seqp->state != AL_PLAYING) || (seq == NULL)) + return; + + /* Get the next event time in ticks. */ + /* If false is returned, then there is no next delta (ie. end of sequence reached). */ + if (!__alSeqNextDelta(seq, &deltaTicks)) + return; + + /* Handle loops. */ + if (seqp->loopCount) + { + /* Assume that the loop end falls on a MIDI event. Delta time + will be correct even if we loop */ + if (alSeqGetTicks(seq) + deltaTicks >= seqp->loopEnd->curTicks) + { + alSeqSetLoc(seq, seqp->loopStart); + + if (seqp->loopCount != -1) + seqp->loopCount--; + } + } + + evt.type = AL_SEQ_REF_EVT; + alEvtqPostEvent(&seqp->evtq, &evt, deltaTicks * seqp->uspt); +} \ No newline at end of file diff --git a/src/core1/n_env.c b/src/core1/n_env.c new file mode 100644 index 00000000..f872b84a --- /dev/null +++ b/src/core1/n_env.c @@ -0,0 +1,12 @@ +#include +#include "functions.h" +#include "variables.h" + + +#pragma GLOBAL_ASM("asm/nonmatchings/core1/n_env/func_80260860.s") + +#pragma GLOBAL_ASM("asm/nonmatchings/core1/n_env/func_802609E0.s") + +#pragma GLOBAL_ASM("asm/nonmatchings/core1/n_env/func_80260BD4.s") + +#pragma GLOBAL_ASM("asm/nonmatchings/core1/n_env/n_alEnvmixerPull.s") diff --git a/src/core2/code_AEDA0.c b/src/core2/code_AEDA0.c index 8bd8815a..0577e7d3 100644 --- a/src/core2/code_AEDA0.c +++ b/src/core2/code_AEDA0.c @@ -2,6 +2,21 @@ #include "functions.h" #include "variables.h" +Mtx *func_8024DD9C(void); +void func_80251BCC(Mtx *); +void func_80252330(f32, f32, f32); +void mlMtxApply(Mtx *); +void func_803382D8(s32 arg0); +void func_803382E4(s32 arg0); +void func_803382F0(s32 arg0); +void func_803382FC(s32 arg0); +void func_80338308(s32 arg0, s32 arg1); + +/* .data */ +extern Gfx D_80370260[]; +extern Gfx D_80370290[]; +extern Gfx D_803702C0[]; +extern Gfx D_80370308[]; extern u8 D_80370338[4]; extern u8 D_8037033C; @@ -21,15 +36,136 @@ s32 D_8038363C; s32 D_80383640; s32 D_80383644; +void func_803380F8(Gfx **gfx, Mtx **mtx, f32 arg2[3]); +void func_803381B4(Gfx **gfx, Mtx **mtx, f32 arg2[3]); + /* .code */ -#pragma GLOBAL_ASM("asm/nonmatchings/core2/code_AEDA0/func_80335D30.s") +void func_80335D30(Gfx **gfx){ + gDPPipeSync((*gfx)++); + if (D_80370338[0] == 0) { + gDPSetColorDither((*gfx)++, G_CD_DISABLE); + }//L80335D7C + switch(D_80383634 + 1){ + case 0: + return; + + case 15: + gSPDisplayList((*gfx)++, D_803702C0); + gDPSetPrimColor((*gfx)++, 0, 0, D_80383610, D_80383614, D_80383618, 0xFF); + return; + + case 12: + gSPDisplayList((*gfx)++, D_80370290); + gDPSetCombineMode((*gfx)++, G_CC_MODULATEIA_PRIM, G_CC_MODULATEIA_PRIM); + gDPSetPrimColor((*gfx)++, 0, 0, D_80383610, D_80383614, D_80383618, 0xFF); + return; + + case 10: + gSPDisplayList((*gfx)++, D_80370260); + gDPSetCombineLERP((*gfx)++, PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0, PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0); + gDPSetPrimColor((*gfx)++, 0, 0, D_80383610, D_80383614, D_80383618, D_8038363C); + gDPSetEnvColor((*gfx)++, D_80383620, D_80383624, D_80383628, 0xFF); + return; + + case 16: + gSPDisplayList((*gfx)++, D_80370290); + gDPSetCombineLERP((*gfx)++, PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0, PRIMITIVE, ENVIRONMENT, TEXEL0, ENVIRONMENT, TEXEL0, 0, PRIMITIVE, 0); + gDPSetPrimColor((*gfx)++, 0, 0, D_80383610, D_80383614, D_80383618, D_8038363C); + gDPSetEnvColor((*gfx)++, D_80383620, D_80383624, D_80383628, 0xFF); + return; + + case 8: + if (D_8038361C != 0) { + gSPDisplayList((*gfx)++, D_80370308); + gDPSetCombineLERP((*gfx)++, TEXEL0, 0, PRIMITIVE, 0, TEXEL0, 0, PRIMITIVE, 0, PRIMITIVE, COMBINED, ENVIRONMENT, COMBINED, 0, 0, 0, COMBINED); + gDPSetEnvColor((*gfx)++, D_8038361C, D_8038361C, D_8038361C, 0xFF); + } else { + gSPDisplayList((*gfx)++, D_80370260); + gDPSetCombineMode((*gfx)++, G_CC_MODULATEIA_PRIM, G_CC_MODULATEIA_PRIM); + } + gDPSetPrimColor((*gfx)++, 0, 0, D_80383610, D_80383614, D_80383618, D_8038363C); + return; + + case 7: + if (D_8038361C != 0) { + gSPDisplayList((*gfx)++, D_80370308); + gDPSetCombineLERP((*gfx)++, TEXEL0, 0, PRIMITIVE, 0, 0, 0, 0, TEXEL0, PRIMITIVE, COMBINED, PRIMITIVE_ALPHA, COMBINED, 0, 0, 0, COMBINED); + gDPSetPrimColor((*gfx)++, 0, 0, D_80383610, D_80383614, D_80383618, D_8038361C); + } else { + gSPDisplayList((*gfx)++, D_80370260); + gDPSetCombineMode((*gfx)++, G_CC_MODULATEIA_PRIM, G_CC_MODULATEIA_PRIM); + gDPSetPrimColor((*gfx)++, 0, 0, D_80383610, D_80383614, D_80383618, 0xFF); + } + return; + + case 6: + gSPDisplayList((*gfx)++, D_80370260); + gDPSetCombineMode((*gfx)++, G_CC_MODULATEIA_PRIM, G_CC_MODULATEIA_PRIM); + gDPSetPrimColor((*gfx)++, 0, 0, D_80383610, D_80383614, D_80383618, D_8038363C); + return; + + case 13: + gSPDisplayList((*gfx)++, D_80370290); + gDPSetCombineMode((*gfx)++, G_CC_MODULATEIA_PRIM, G_CC_MODULATEIA_PRIM); + gDPSetPrimColor((*gfx)++, 0, 0, D_80383610, D_80383614, D_80383618, D_8038363C); + return; + + case 5: + gSPDisplayList((*gfx)++, D_80370260); + gDPSetCombineMode((*gfx)++, G_CC_MODULATEIA_PRIM, G_CC_MODULATEIA_PRIM); + gDPSetPrimColor((*gfx)++, 0, 0, D_80383610, D_80383614, D_80383618, 0xFF); + return; + + case 9: + gSPDisplayList((*gfx)++, D_80370260); + gDPSetCombineMode((*gfx)++, G_CC_MODULATEIA_PRIM, G_CC_MODULATEIA_PRIM); + gDPSetPrimColor((*gfx)++, 0, 0, D_80383630, D_80383630, D_80383630, D_8038363C); + return; + + case 14: + gSPDisplayList((*gfx)++, D_80370290); + gDPSetCombineMode((*gfx)++, G_CC_MODULATEIA_PRIM, G_CC_MODULATEIA_PRIM); + gDPSetPrimColor((*gfx)++, 0, 0, D_80383630, D_80383630, D_80383630, D_8038363C); + return; + + case 1: + gSPDisplayList((*gfx)++, D_80370260); + gDPSetCombineMode((*gfx)++, G_CC_MODULATEIA_PRIM, G_CC_MODULATEIA_PRIM); + gDPSetPrimColor((*gfx)++, 0, 0, D_80383630, D_80383630, D_80383630, 0xFF); + return; + + case 2: + gSPDisplayList((*gfx)++, D_80370260); + gDPSetCombineLERP((*gfx)++, 0, 0, 0, PRIMITIVE, TEXEL0, 0, PRIMITIVE, 0, 0, 0, 0, PRIMITIVE, TEXEL0, 0, PRIMITIVE, 0); + gDPSetPrimColor((*gfx)++, 0, 0, 0, 0, 0, D_8038363C); + return; + + case 11: + gSPDisplayList((*gfx)++, D_80370290); + gDPSetCombineLERP((*gfx)++, 0, 0, 0, PRIMITIVE, TEXEL0, 0, PRIMITIVE, 0, 0, 0, 0, PRIMITIVE, TEXEL0, 0, PRIMITIVE, 0); + gDPSetPrimColor((*gfx)++, 0, 0, 0, 0, 0, D_8038363C); + return; + + case 4: + gSPDisplayList((*gfx)++, D_80370260); + gDPSetCombineMode((*gfx)++, G_CC_MODULATEIA_PRIM, G_CC_MODULATEIA_PRIM); + gDPSetPrimColor((*gfx)++, 0, 0, D_80383620, D_80383624, D_80383628, D_8038362C); + return; + + default://L80336814 + gSPDisplayList((*gfx)++, D_80370260); + gDPSetCombineLERP((*gfx)++, 0, 0, 0, TEXEL0, 0, 0, 0, PRIMITIVE, 0, 0, 0, TEXEL0, 0, 0, 0, PRIMITIVE); + gDPSetPrimColor((*gfx)++, 0, 0, 0, 0, 0, 0xFF); + return; + } +} void func_8033687C( Gfx **gfx ) { /* Turn off texturing */ gDPPipeSync((*gfx)++); if (D_80370338[0] == 0) { - gDPSetColorDither((*gfx)++, 0); + gDPSetColorDither((*gfx)++, G_CD_MAGICSQ); D_80370338[0] = 1; } @@ -363,19 +499,45 @@ void func_80337B68(Gfx **gfx, Vtx **vtx, Struct84s *texture_list, s32 texture_in } #endif -#pragma GLOBAL_ASM("asm/nonmatchings/core2/code_AEDA0/func_80338048.s") +void func_80338048(Gfx **gfx, Mtx **mtx, Vtx **vtx, f32 arg3[3], Struct84s *arg4, s32 arg5) { + func_803380F8(gfx, mtx, arg3); + func_80337B68(gfx, vtx, arg4, arg5); + gSPPopMatrix((*gfx)++, G_MTX_MODELVIEW); +} -#pragma GLOBAL_ASM("asm/nonmatchings/core2/code_AEDA0/func_803380A0.s") +void func_803380A0(Gfx **gfx, Mtx **mtx, Vtx **vtx, f32 arg3[3], Struct84s *arg4, s32 arg5) { + func_803381B4(gfx, mtx, arg3); + func_80337B68(gfx, vtx, arg4, arg5); + gSPPopMatrix((*gfx)++, G_MTX_MODELVIEW); +} -#pragma GLOBAL_ASM("asm/nonmatchings/core2/code_AEDA0/func_803380F8.s") +void func_803380F8(Gfx **gfx, Mtx **mtx, f32 arg2[3]) { + f32 sp2C[3]; + f32 sp20[3]; -#pragma GLOBAL_ASM("asm/nonmatchings/core2/code_AEDA0/func_803381B4.s") + func_8024C5CC(sp2C); + sp20[0] = arg2[0] - sp2C[0]; + sp20[1] = arg2[1] - sp2C[1]; + sp20[2] = arg2[2] - sp2C[2]; + func_80251BCC(func_8024DD90()); + func_80252330(sp20[0], sp20[1], sp20[2]); + mlMtxApply(*mtx); + gSPMatrix((*gfx)++, (*mtx)++, G_MTX_PUSH | G_MTX_LOAD | G_MTX_MODELVIEW); +} -void func_803382D8(s32 arg0); -void func_803382E4(s32 arg0); -void func_803382F0(s32 arg0); -void func_803382FC(s32 arg0); -void func_80338308(s32 arg0, s32 arg1); +void func_803381B4(Gfx **gfx, Mtx **mtx, f32 arg2[3]) { + f32 sp2C[3]; + f32 sp20[3]; + + func_8024C5CC(sp2C); + sp20[0] = arg2[0] - sp2C[0]; + sp20[1] = arg2[1] - sp2C[1]; + sp20[2] = arg2[2] - sp2C[2]; + func_80251BCC(func_8024DD9C()); + func_80252330(sp20[0], sp20[1], sp20[2]); + mlMtxApply(*mtx); + gSPMatrix((*gfx)++, (*mtx)++, G_MTX_PUSH | G_MTX_LOAD | G_MTX_MODELVIEW); +} void func_80338270(){ func_803382D8(0xFF); @@ -425,9 +587,13 @@ void func_80338338(s32 r, s32 g, s32 b){ D_80383618 = b; } -#pragma GLOBAL_ASM("asm/nonmatchings/core2/code_AEDA0/func_80338354.s") +void func_80338354(s32 arg0){ + D_8038361C = arg0 / 8 ; +} -#pragma GLOBAL_ASM("asm/nonmatchings/core2/code_AEDA0/func_80338370.s") +void func_80338370(void){ + D_80370338[0] = 0; +} void func_8033837C(s32 arg0){ D_8037033C = arg0; diff --git a/subyaml/core1.us.v10.yaml b/subyaml/core1.us.v10.yaml index 0161feef..b1fe6ff6 100644 --- a/subyaml/core1.us.v10.yaml +++ b/subyaml/core1.us.v10.yaml @@ -52,6 +52,8 @@ segments: - [0x13680, c, code_13680] - [0x136D0, c, code_136D0] - [0x13990, c, code_13990] + - [0x155F0, hasm, code_155F0] #DONE + - [0x15630, c, code_15630] #DONE - [0x15770, c, code_15770] - [0x15B30, c, code_15B30] #DONE - [0x16A50, c, memory] @@ -97,7 +99,8 @@ segments: - [0x227F0, c, done/audio/n_drvrNew] #DONE - [0x22D50, c, done/audio/n_save] #DONE - [0x22DA0, c, done/audio/n_envresample] #DONE - - [0x22E40, c, code_22E40] #n_seqplayer.c + - [0x22E40, c, n_env] + - [0x237F0, c, done/audio/n_seqplayer] - [0x25360, c, done/audio/n_synstartvoiceparam] #DONE - [0x25440, c, done/audio/n_mainbus] #DONE - [0x254C0, c, done/audio/n_load] #DONE @@ -267,7 +270,7 @@ segments: - [0x39B60, .data, done/io/vimodempallan1] - [0x39B60, .data, done/io/vimodentsclan1] - [0x39C00, bin, data_39C00] # .rodata, code_1D00] - - [0x39C20, bin, data_39C20] # .rodata, code_31C0] + - [0x39C20, .rodata, code_31C0] - [0x39C30, bin, data_39C30] # .rodata, code_3A70] - [0x39CA0, bin, data_39CA0] # .rodata, code_72B0] - [0x39CD0, bin, data_39CD0] # .rodata, code_7F60] @@ -285,7 +288,7 @@ segments: - [0x3AD30, bin, data_3AD30] - [0x3AD60, .rodata, done/audio/n_drvrNew] - [0x3AD80, bin, data_3AD80] - - [0x3ADD0, bin, data_3ADD0] # .rodata, code_22E40] + - [0x3ADD0, .rodata, done/audio/n_seqplayer] - [0x3B180, .rodata, done/audio/n_resample] - [0x3B190, .rodata, done/gu/sinf] - [0x3B1E0, .rodata, done/audio/cents2ratio] diff --git a/symbol_addrs.core1.us.v10.txt b/symbol_addrs.core1.us.v10.txt index 6b2509e9..811071f4 100644 --- a/symbol_addrs.core1.us.v10.txt +++ b/symbol_addrs.core1.us.v10.txt @@ -35,7 +35,7 @@ mlMtxRotYaw = 0x80251D84; mlMtxRotRoll = 0x80251E80; mlMtxRotate = 0x80252188; mlMtxScale_xyz = 0x802521C0; -mlMtxScale = 0x80252280; +mlMtxScale = 0x80252280; mlMtx_apply_vec3s = 0x802525A4; mlMtxTranslate = 0x80252980;