mirror of
https://github.com/coop-deluxe/sm64coopdx.git
synced 2024-10-19 11:42:39 +00:00
527 lines
19 KiB
C
527 lines
19 KiB
C
//! Copt inlining for US/JP. Here be dragons
|
|
|
|
#include <ultra64.h>
|
|
#include <macros.h>
|
|
|
|
#include "heap.h"
|
|
#include "data.h"
|
|
#include "load.h"
|
|
#include "seqplayer.h"
|
|
#include "external.h"
|
|
#include "effects.h"
|
|
|
|
#define PORTAMENTO_IS_SPECIAL(x) ((x).mode & 0x80)
|
|
#define PORTAMENTO_MODE(x) ((x).mode & ~0x80)
|
|
#define PORTAMENTO_MODE_1 1
|
|
#define PORTAMENTO_MODE_2 2
|
|
#define PORTAMENTO_MODE_3 3
|
|
#define PORTAMENTO_MODE_4 4
|
|
#define PORTAMENTO_MODE_5 5
|
|
|
|
#define COPT 0
|
|
#if COPT
|
|
#define M64_READ_U8(state, dst) \
|
|
dst = m64_read_u8(state);
|
|
#else
|
|
#define M64_READ_U8(state, dst) \
|
|
{ \
|
|
u8 * _ptr_pc; \
|
|
u8 _pc; \
|
|
_ptr_pc = (*state).pc; \
|
|
((*state).pc)++; \
|
|
_pc = *_ptr_pc; \
|
|
dst = _pc; \
|
|
}
|
|
#endif
|
|
|
|
|
|
#if COPT
|
|
#define M64_READ_S16(state, dst) \
|
|
dst = m64_read_s16(state);
|
|
#else
|
|
#define M64_READ_S16(state, dst) \
|
|
{ \
|
|
s16 _ret; \
|
|
_ret = *(*state).pc << 8; \
|
|
((*state).pc)++; \
|
|
_ret = *(*state).pc | _ret; \
|
|
((*state).pc)++; \
|
|
dst = _ret; \
|
|
}
|
|
#endif
|
|
#if COPT
|
|
#define M64_READ_COMPRESSED_U16(state, dst) \
|
|
dst = m64_read_compressed_u16(state);
|
|
#else
|
|
#define M64_READ_COMPRESSED_U16(state, dst) \
|
|
{ \
|
|
u16 ret = *(state->pc++); \
|
|
if (ret & 0x80) { \
|
|
ret = (ret << 8) & 0x7f00; \
|
|
ret = *(state->pc++) | ret; \
|
|
} \
|
|
dst = ret; \
|
|
}
|
|
#endif
|
|
|
|
#if COPT
|
|
#define GET_INSTRUMENT(seqChannel, instId, _instOut, _adsr, dst, l) \
|
|
dst = get_instrument(seqChannel, instId, _instOut, _adsr);
|
|
#else
|
|
#define GET_INSTRUMENT(seqChannel, instId, _instOut, _adsr, dst, l) \
|
|
{ \
|
|
struct AdsrSettings *adsr = _adsr; \
|
|
struct Instrument **instOut = _instOut;\
|
|
u8 _instId = instId; \
|
|
struct Instrument *inst; \
|
|
UNUSED u32 pad; \
|
|
/* copt inlines instId here */ \
|
|
if (instId >= gCtlEntries[(*seqChannel).bankId].numInstruments) { \
|
|
_instId = gCtlEntries[(*seqChannel).bankId].numInstruments; \
|
|
if (_instId == 0) { \
|
|
dst = 0; \
|
|
goto ret ## l; \
|
|
} \
|
|
_instId--; \
|
|
} \
|
|
inst = gCtlEntries[(*seqChannel).bankId].instruments[_instId]; \
|
|
if (inst == NULL) { \
|
|
while (_instId != 0xff) { \
|
|
inst = gCtlEntries[(*seqChannel).bankId].instruments[_instId]; \
|
|
if (inst != NULL) { \
|
|
goto gi ## l; \
|
|
} \
|
|
_instId--; \
|
|
} \
|
|
gi ## l:; \
|
|
} \
|
|
if (((uintptr_t) gBankLoadedPool.persistent.pool.start <= (uintptr_t) inst \
|
|
&& (uintptr_t) inst <= (uintptr_t)(gBankLoadedPool.persistent.pool.start \
|
|
+ gBankLoadedPool.persistent.pool.size)) \
|
|
|| ((uintptr_t) gBankLoadedPool.temporary.pool.start <= (uintptr_t) inst \
|
|
&& (uintptr_t) inst <= (uintptr_t)(gBankLoadedPool.temporary.pool.start \
|
|
+ gBankLoadedPool.temporary.pool.size))) { \
|
|
(*adsr).envelope = (*inst).envelope; \
|
|
(*adsr).releaseRate = (*inst).releaseRate; \
|
|
*instOut = inst; \
|
|
_instId++; \
|
|
goto ret ## l; \
|
|
} \
|
|
gAudioErrorFlags = _instId + 0x20000; \
|
|
*instOut = NULL; \
|
|
ret ## l: ; \
|
|
}
|
|
#endif
|
|
|
|
#ifdef VERSION_EU
|
|
#define PORTAMENTO_TGT_NOTE cmd
|
|
#define DRUM_INDEX cmd
|
|
#define SEMITONE cmd
|
|
#define USED_SEMITONE vel
|
|
#else
|
|
#define PORTAMENTO_TGT_NOTE portamentoTargetNote
|
|
#define DRUM_INDEX cmdSemitone
|
|
#define SEMITONE cmdSemitone
|
|
#define USED_SEMITONE usedSemitone
|
|
#endif
|
|
|
|
void seq_channel_layer_process_script(struct SequenceChannelLayer *layer) {
|
|
struct SequencePlayer *seqPlayer; // sp5C, t4
|
|
struct SequenceChannel *seqChannel; // sp58, t5
|
|
struct M64ScriptState *state; // v0
|
|
struct Portamento *portamento; // v0
|
|
struct AudioBankSound *sound; // v0
|
|
struct Instrument *instrument; // v1
|
|
struct Drum *drum;
|
|
UNUSED s32 pad[1];
|
|
u8 sameSound; // sp3F
|
|
UNUSED u8 allocNewNote; // sp3D, t0
|
|
u8 cmd; // a0 sp3E, EU s2
|
|
UNUSED u8 loBits;
|
|
u16 sp3A; // t2, a0, a1
|
|
UNUSED s32 pad2[1];
|
|
s32 vel; // sp30, t3
|
|
UNUSED s32 pad3[1];
|
|
f32 freqScale; // sp28, f0
|
|
f32 sp24;
|
|
u8 temp8;
|
|
UNUSED u8 semitone; // v0
|
|
s32 usedSemitone; // a1
|
|
f32 temp_f12;
|
|
f32 temp_f2;
|
|
s32 temp_a0_5;
|
|
UNUSED u8 drumIndex; // t0
|
|
UNUSED s32 cmdBase; // t1
|
|
u8 temp_a0_6;
|
|
u8 portamentoTargetNote; // t7
|
|
UNUSED s32 bankId; // a3
|
|
u8 instId; // v0
|
|
u8 cmdSemitone; // v1
|
|
f32 tuning; // f0
|
|
|
|
// inlined copt var that gets pulled out to the rest of the function
|
|
unsigned char _Kqi6;
|
|
|
|
//! Copt: manually inline these functions in the scope of this routine
|
|
#ifdef __sgi
|
|
#pragma inline routine(m64_read_u8)
|
|
#pragma inline routine(m64_read_compressed_u16)
|
|
#pragma inline routine(m64_read_s16)
|
|
#pragma inline routine(get_instrument)
|
|
#endif
|
|
|
|
sameSound = TRUE;
|
|
if (layer->enabled == FALSE) {
|
|
return;
|
|
}
|
|
|
|
if (layer->delay > 1) {
|
|
layer->delay--;
|
|
if (!layer->stopSomething && layer->delay <= layer->duration) {
|
|
seq_channel_layer_note_decay(layer);
|
|
layer->stopSomething = TRUE;
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (!layer->continuousNotes) {
|
|
seq_channel_layer_note_decay(layer);
|
|
}
|
|
|
|
if (PORTAMENTO_MODE(layer->portamento) == PORTAMENTO_MODE_1 ||
|
|
PORTAMENTO_MODE(layer->portamento) == PORTAMENTO_MODE_2) {
|
|
layer->portamento.mode = 0;
|
|
}
|
|
|
|
seqChannel = (*(layer)).seqChannel;
|
|
seqPlayer = (*(seqChannel)).seqPlayer;
|
|
for (;;) {
|
|
state = &layer->scriptState;
|
|
//M64_READ_U8(state, cmd);
|
|
// manually inlined because we need _Kqi6 :(
|
|
{
|
|
u8 *_ptr_pc;
|
|
_ptr_pc = (*state).pc;
|
|
((*state).pc)++;
|
|
//cmd = *_ptr_pc;
|
|
|
|
_Kqi6 = *_ptr_pc;
|
|
cmd = _Kqi6;
|
|
}
|
|
|
|
if (cmd <= 0xc0) {
|
|
break;
|
|
}
|
|
|
|
switch (_Kqi6)
|
|
{
|
|
case 0xff: // layer_end; function return or end of script
|
|
if (state->depth == 0) {
|
|
// N.B. this function call is *not* inlined even though it's
|
|
// within the same file, unlike in the rest of this function.
|
|
seq_channel_layer_disable(layer);
|
|
return;
|
|
}
|
|
state->depth--, state->pc = state->stack[state->depth];
|
|
break;
|
|
|
|
case 0xfc: // layer_call
|
|
M64_READ_S16(state, sp3A);
|
|
state->depth++, state->stack[state->depth - 1] = state->pc;
|
|
state->pc = seqPlayer->seqData + sp3A;
|
|
break;
|
|
|
|
case 0xf8: // layer_loop; loop start, N iterations (or 256 if N = 0)
|
|
M64_READ_U8(state, state->remLoopIters[state->depth])
|
|
state->depth++, state->stack[state->depth - 1] = state->pc;
|
|
break;
|
|
|
|
case 0xf7: // layer_loopend
|
|
if (--state->remLoopIters[state->depth - 1] != 0) {
|
|
state->pc = state->stack[state->depth - 1];
|
|
} else {
|
|
state->depth--;
|
|
}
|
|
break;
|
|
|
|
case 0xfb: // layer_jump
|
|
M64_READ_S16(state, sp3A);
|
|
state->pc = seqPlayer->seqData + sp3A;
|
|
break;
|
|
|
|
case 0xc1: // layer_setshortnotevelocity
|
|
case 0xca: // layer_setpan
|
|
temp_a0_5 = *(state->pc++);
|
|
if (cmd == 0xc1) {
|
|
layer->velocitySquare = (f32)(temp_a0_5 * temp_a0_5);
|
|
} else {
|
|
layer->pan = (f32) temp_a0_5 / US_FLOAT(128.0);
|
|
}
|
|
break;
|
|
|
|
case 0xc2: // layer_transpose; set transposition in semitones
|
|
case 0xc9: // layer_setshortnoteduration
|
|
temp_a0_6 = *(state->pc++);
|
|
if (cmd == 0xc9) {
|
|
layer->noteDuration = temp_a0_6;
|
|
} else {
|
|
layer->transposition = temp_a0_6;
|
|
}
|
|
break;
|
|
|
|
case 0xc4: // layer_somethingon
|
|
case 0xc5: // layer_somethingoff
|
|
//! copt needs a ternary:
|
|
//layer->continuousNotes = (cmd == 0xc4) ? TRUE : FALSE;
|
|
if (cmd == 0xc4) {
|
|
temp8 = TRUE;
|
|
} else {
|
|
temp8 = FALSE;
|
|
}
|
|
layer->continuousNotes = temp8;
|
|
seq_channel_layer_note_decay(layer);
|
|
break;
|
|
|
|
case 0xc3: // layer_setshortnotedefaultplaypercentage
|
|
M64_READ_COMPRESSED_U16(state, sp3A)
|
|
layer->shortNoteDefaultPlayPercentage = sp3A;
|
|
break;
|
|
|
|
case 0xc6: // layer_setinstr
|
|
M64_READ_U8(state, instId);
|
|
if (instId < 127) {
|
|
GET_INSTRUMENT(seqChannel, instId, &(*layer).instrument, &(*layer).adsr, instId, 1);
|
|
}
|
|
break;
|
|
|
|
case 0xc7: // layer_portamento
|
|
M64_READ_U8(state, (*layer).portamento.mode);
|
|
M64_READ_U8(state, PORTAMENTO_TGT_NOTE);
|
|
PORTAMENTO_TGT_NOTE = PORTAMENTO_TGT_NOTE + (*layer).transposition + (*seqPlayer).transposition + (*seqChannel).transposition;
|
|
if (PORTAMENTO_TGT_NOTE >= 0x80) {
|
|
PORTAMENTO_TGT_NOTE = 0;
|
|
}
|
|
layer->portamentoTargetNote = PORTAMENTO_TGT_NOTE;
|
|
|
|
// If special, the next param is u8 instead of var
|
|
if (PORTAMENTO_IS_SPECIAL((*(layer)).portamento)) {
|
|
layer->portamentoTime = *((state)->pc++);
|
|
break;
|
|
}
|
|
|
|
M64_READ_COMPRESSED_U16(state, sp3A)
|
|
layer->portamentoTime = sp3A;
|
|
break;
|
|
|
|
case 0xc8: // layer_disableportamento
|
|
layer->portamento.mode = 0;
|
|
break;
|
|
|
|
default:
|
|
switch (cmd & 0xf0) {
|
|
case 0xd0: // layer_setshortnotevelocityfromtable
|
|
sp3A = seqPlayer->shortNoteVelocityTable[cmd & 0xf];
|
|
(*(layer)).velocitySquare = (f32)(sp3A * sp3A);
|
|
break;
|
|
case 0xe0: // layer_setshortnotedurationfromtable
|
|
(*(layer)).noteDuration = seqPlayer->shortNoteDurationTable[cmd & 0xf];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (cmd == 0xc0) // layer_delay
|
|
{
|
|
M64_READ_COMPRESSED_U16(state, layer->delay);
|
|
layer->stopSomething = TRUE;
|
|
} else {
|
|
layer->stopSomething = FALSE;
|
|
|
|
if (seqChannel->largeNotes == TRUE) {
|
|
switch (cmd & 0xc0) {
|
|
case 0x00: // layer_note0 (play percentage, velocity, duration)
|
|
M64_READ_COMPRESSED_U16(state, sp3A)
|
|
vel = *((*state).pc++);
|
|
layer->noteDuration = *(state->pc++);
|
|
layer->playPercentage = sp3A;
|
|
goto l1090;
|
|
|
|
case 0x40: // layer_note1 (play percentage, velocity)
|
|
M64_READ_COMPRESSED_U16(state, sp3A)
|
|
vel = *(state->pc++);
|
|
layer->noteDuration = 0;
|
|
layer->playPercentage = sp3A;
|
|
goto l1090;
|
|
|
|
|
|
case 0x80: // layer_note2 (velocity, duration; uses last play percentage)
|
|
sp3A = layer->playPercentage;
|
|
vel = *(state->pc++);
|
|
layer->noteDuration = *(state->pc++);
|
|
goto l1090;
|
|
}
|
|
l1090:
|
|
cmdSemitone = (cmd - (cmd & 0xc0));
|
|
layer->velocitySquare = vel * vel;
|
|
} else {
|
|
switch (cmd & 0xc0) {
|
|
case 0x00: // play note, type 0 (play percentage)
|
|
M64_READ_COMPRESSED_U16(state, sp3A)
|
|
layer->playPercentage = sp3A;
|
|
break;
|
|
|
|
case 0x40: // play note, type 1 (uses default play percentage)
|
|
sp3A = layer->shortNoteDefaultPlayPercentage;
|
|
break;
|
|
|
|
case 0x80: // play note, type 2 (uses last play percentage)
|
|
sp3A = layer->playPercentage;
|
|
break;
|
|
}
|
|
|
|
cmdSemitone = cmd - (cmd & 0xc0);
|
|
}
|
|
|
|
layer->delay = sp3A;
|
|
layer->duration = layer->noteDuration * sp3A / 256;
|
|
if ((seqPlayer->muted && (seqChannel->muteBehavior & MUTE_BEHAVIOR_STOP_NOTES) != 0)
|
|
|| seqChannel->stopSomething2
|
|
|| !seqChannel->hasInstrument
|
|
) {
|
|
layer->stopSomething = TRUE;
|
|
} else {
|
|
if (seqChannel->instOrWave == 0) { // drum
|
|
//DRUM_INDEX = cmdSemitone;
|
|
DRUM_INDEX += (*seqChannel).transposition + (*layer).transposition;
|
|
if (DRUM_INDEX >= gCtlEntries[seqChannel->bankId].numDrums) {
|
|
DRUM_INDEX = gCtlEntries[seqChannel->bankId].numDrums;
|
|
if (DRUM_INDEX == 0) {
|
|
// this goto looks a bit like a function return...
|
|
layer->stopSomething = TRUE;
|
|
goto skip;
|
|
}
|
|
|
|
DRUM_INDEX--;
|
|
}
|
|
|
|
drum = gCtlEntries[seqChannel->bankId].drums[DRUM_INDEX];
|
|
if (drum == NULL) {
|
|
layer->stopSomething = TRUE;
|
|
} else {
|
|
layer->adsr.envelope = drum->envelope;
|
|
layer->adsr.releaseRate = drum->releaseRate;
|
|
layer->pan = FLOAT_CAST(drum->pan) / US_FLOAT(128.0);
|
|
layer->sound = &drum->sound;
|
|
layer->freqScale = layer->sound->tuning;
|
|
}
|
|
|
|
skip:;
|
|
} else { // instrument
|
|
//SEMITONE = cmdSemitone;
|
|
SEMITONE += (*(seqPlayer)).transposition + (*(seqChannel)).transposition + (*(layer)).transposition;
|
|
if (SEMITONE >= 0x80) {
|
|
layer->stopSomething = TRUE;
|
|
} else {
|
|
instrument = layer->instrument;
|
|
if (instrument == NULL) {
|
|
instrument = seqChannel->instrument;
|
|
}
|
|
|
|
if (layer->portamento.mode != 0) {
|
|
//! copt needs a ternary:
|
|
//usedSemitone = (layer->portamentoTargetNote < SEMITONE) ? SEMITONE : layer->portamentoTargetNote;
|
|
if (layer->portamentoTargetNote < SEMITONE) {
|
|
USED_SEMITONE = SEMITONE;
|
|
} else {
|
|
USED_SEMITONE = layer->portamentoTargetNote;
|
|
}
|
|
|
|
if (instrument != NULL) {
|
|
sound = (u8) USED_SEMITONE < instrument->normalRangeLo ? &instrument->lowNotesSound
|
|
: (u8) USED_SEMITONE <= instrument->normalRangeHi ?
|
|
&instrument->normalNotesSound : &instrument->highNotesSound;
|
|
|
|
sameSound = (sound == (*layer).sound);
|
|
layer->sound = sound;
|
|
tuning = (*sound).tuning;
|
|
} else {
|
|
layer->sound = NULL;
|
|
tuning = 1.0f;
|
|
}
|
|
|
|
temp_f2 = gNoteFrequencies[SEMITONE] * tuning;
|
|
temp_f12 = gNoteFrequencies[layer->portamentoTargetNote] * tuning;
|
|
|
|
portamento = &layer->portamento;
|
|
switch (PORTAMENTO_MODE(layer->portamento)) {
|
|
case PORTAMENTO_MODE_1:
|
|
case PORTAMENTO_MODE_3:
|
|
case PORTAMENTO_MODE_5:
|
|
sp24 = temp_f2;
|
|
freqScale = temp_f12;
|
|
goto l13cc;
|
|
|
|
case PORTAMENTO_MODE_2:
|
|
case PORTAMENTO_MODE_4:
|
|
freqScale = temp_f2;
|
|
sp24 = temp_f12;
|
|
goto l13cc;
|
|
}
|
|
l13cc:
|
|
portamento->extent = sp24 / freqScale - US_FLOAT(1.0);
|
|
if (PORTAMENTO_IS_SPECIAL((*(layer)).portamento)) {
|
|
portamento->speed = US_FLOAT(32512.0) * FLOAT_CAST((*(seqPlayer)).tempo)
|
|
/ ((f32)(*(layer)).delay * (f32) gTempoInternalToExternal
|
|
* FLOAT_CAST((*(layer)).portamentoTime));
|
|
} else {
|
|
portamento->speed = US_FLOAT(127.0) / FLOAT_CAST((*(layer)).portamentoTime);
|
|
}
|
|
portamento->cur = 0.0f;
|
|
layer->freqScale = freqScale;
|
|
if (PORTAMENTO_MODE((*(layer)).portamento) == PORTAMENTO_MODE_5) {
|
|
layer->portamentoTargetNote = SEMITONE;
|
|
}
|
|
} else if (instrument != NULL) {
|
|
sound = SEMITONE < instrument->normalRangeLo ?
|
|
&instrument->lowNotesSound : SEMITONE <= instrument->normalRangeHi ?
|
|
&instrument->normalNotesSound : &instrument->highNotesSound;
|
|
|
|
sameSound = (sound == (*(layer)).sound);
|
|
layer->sound = sound;
|
|
layer->freqScale = gNoteFrequencies[SEMITONE] * (*(sound)).tuning;
|
|
} else {
|
|
layer->sound = NULL;
|
|
layer->freqScale = gNoteFrequencies[SEMITONE];
|
|
}
|
|
}
|
|
}
|
|
layer->delayUnused = layer->delay;
|
|
}
|
|
}
|
|
|
|
if (layer->stopSomething == TRUE) {
|
|
if (layer->note != NULL || layer->continuousNotes) {
|
|
seq_channel_layer_note_decay(layer);
|
|
}
|
|
return;
|
|
}
|
|
|
|
cmd = FALSE;
|
|
if (!layer->continuousNotes) {
|
|
cmd = TRUE;
|
|
} else if (layer->note == NULL || layer->status == SOUND_LOAD_STATUS_NOT_LOADED) {
|
|
cmd = TRUE;
|
|
} else if (sameSound == FALSE) {
|
|
seq_channel_layer_note_decay(layer);
|
|
cmd = TRUE;
|
|
} else if (layer->sound == NULL) {
|
|
init_synthetic_wave(layer->note, layer);
|
|
}
|
|
|
|
if (cmd != FALSE) {
|
|
(*(layer)).note = alloc_note(layer);
|
|
}
|
|
|
|
if (layer->note != NULL && layer->note->parentLayer == layer) {
|
|
note_vibrato_init(layer->note);
|
|
}
|
|
}
|