mirror of
https://github.com/pret/pokediamond.git
synced 2026-09-27 22:45:17 -04:00
arm7: decompile SND_unk_037FD440
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -3,20 +3,23 @@
|
||||
|
||||
#include "nitro/types.h"
|
||||
|
||||
#include "nitro/SND_seq_shared.h"
|
||||
#include "nitro/SND_work_shared.h"
|
||||
|
||||
struct SNDTrack *PlayerGetTrack(struct SNDPlayer *player, int track);
|
||||
void PlayerStop(struct SNDPlayer *);
|
||||
void TrackMute(struct SNDTrack *track, struct SNDPlayer *player, int muteMode);
|
||||
void TrackReleaseChannels(struct SNDTrack *track, struct SNDPlayer *player, int release);
|
||||
void TrackFreeChannels(struct SNDTrack *track);
|
||||
BOOL PlayerStepTicks(struct SNDPlayer *player, u32 ticks);
|
||||
void PlayerSetBank(struct SNDPlayer *player, struct SNDBankData *bankData);
|
||||
void PlayerInit(struct SNDPlayer *player, struct SNDBankData *bankData);
|
||||
int AllocateTrack(void);
|
||||
void TrackInit(struct SNDTrack *track);
|
||||
void TrackSetSeq(struct SNDTrack *track, const void *seq, u32 offset);
|
||||
void SeqCacheFetch(const void *addr);
|
||||
u8 SeqReadByte(const void *addr);
|
||||
void TrackStart(struct SNDTrack *track, const void *seq, u32 offset);
|
||||
void SeqCacheFetch(const u8 *addr);
|
||||
u8 SeqReadByte(const u8 *addr);
|
||||
u16 TrackReadU16(struct SNDTrack *track);
|
||||
void PlayerSeqMain(struct SNDPlayer *player);
|
||||
void PlayerUpdateChannelVolume(struct SNDPlayer *player);
|
||||
void PlayerUpdateChannel(struct SNDPlayer *player);
|
||||
|
||||
#endif //GUARD_SND_UNK_H
|
||||
|
||||
@@ -33,7 +33,7 @@ void SND_SeqMain(BOOL step) {
|
||||
if (ply->flags.prepared) {
|
||||
if (step && !ply->flags.paused)
|
||||
PlayerSeqMain(ply);
|
||||
PlayerUpdateChannelVolume(ply);
|
||||
PlayerUpdateChannel(ply);
|
||||
}
|
||||
|
||||
if (ply->flags.active)
|
||||
@@ -50,7 +50,7 @@ void SND_PrepareSeq(int player, const void *seq, u32 offset, struct SNDBankData
|
||||
if (ply->flags.active)
|
||||
PlayerStop(ply);
|
||||
|
||||
PlayerSetBank(ply, bankData);
|
||||
PlayerInit(ply, bankData);
|
||||
|
||||
int allocTrkIdx = AllocateTrack();
|
||||
|
||||
@@ -59,7 +59,7 @@ void SND_PrepareSeq(int player, const void *seq, u32 offset, struct SNDBankData
|
||||
|
||||
struct SNDTrack *trk = &SNDi_Work.tracks[allocTrkIdx];
|
||||
TrackInit(trk);
|
||||
TrackSetSeq(trk, seq, offset);
|
||||
TrackStart(trk, seq, offset);
|
||||
ply->tracks[0] = (u8)allocTrkIdx;
|
||||
SeqCacheFetch(trk->cur);
|
||||
|
||||
|
||||
@@ -0,0 +1,904 @@
|
||||
#include "SND_unk_037FD440.h"
|
||||
|
||||
#include "SND_util.h"
|
||||
#include "SND_lfo.h"
|
||||
#include "SND_exChannel.h"
|
||||
#include "SND_bank.h"
|
||||
|
||||
#define SND_TRACK_MUTE_MODE_UNMUTE 0
|
||||
#define SND_TRACK_MUTE_MODE_MUTE 1
|
||||
#define SND_TRACK_MUTE_MODE_MUTE_RELEASE 2
|
||||
#define SND_TRACK_MUTE_MODE_MUTE_STOP 3
|
||||
|
||||
enum SNDSeqProc {
|
||||
SND_PROC_SKIP_NOTES = 0,
|
||||
SND_PROC_PLAY_NOTES = 1,
|
||||
};
|
||||
|
||||
enum SNDSeqVal {
|
||||
SND_SEQ_VAL_U8 = 0,
|
||||
SND_SEQ_VAL_U16 = 1,
|
||||
SND_SEQ_VAL_VLV = 2,
|
||||
SND_SEQ_VAL_RAN = 3,
|
||||
SND_SEQ_VAL_VAR = 4,
|
||||
};
|
||||
|
||||
#define SND_TIMER_RATE 240
|
||||
|
||||
static struct {
|
||||
const u8 *begin;
|
||||
const u8 *end;
|
||||
union {
|
||||
u8 buf[16];
|
||||
u32 buf32[4];
|
||||
};
|
||||
} sSeqCache;
|
||||
static int sPrintEnabled;
|
||||
|
||||
|
||||
|
||||
static s16 *PlayerGetVariablePointer(const struct SNDPlayer *player, int var);
|
||||
static void TrackUpdateChannel(struct SNDTrack *track, struct SNDPlayer *player, int release);
|
||||
|
||||
// TODO make static
|
||||
void SeqCacheFetch(const u8 *addr) {
|
||||
addr = (const u8 *)((u32)addr & ~3);
|
||||
sSeqCache.begin = addr;
|
||||
sSeqCache.end = sSeqCache.begin + 16;
|
||||
|
||||
const u32 *src = (const u32 *)addr;
|
||||
|
||||
sSeqCache.buf32[0] = src[0];
|
||||
sSeqCache.buf32[1] = src[1];
|
||||
sSeqCache.buf32[2] = src[2];
|
||||
sSeqCache.buf32[3] = src[3];
|
||||
}
|
||||
|
||||
// TODO make static
|
||||
u8 SeqReadByte(const u8 *addr) {
|
||||
if (addr < sSeqCache.begin || addr >= sSeqCache.end)
|
||||
SeqCacheFetch(addr);
|
||||
|
||||
return sSeqCache.buf[(u32)addr - (u32)sSeqCache.begin];
|
||||
}
|
||||
|
||||
static inline u8 TrackReadU8(struct SNDTrack *track) {
|
||||
u8 retval = SeqReadByte(track->cur);
|
||||
track->cur++;
|
||||
return retval;
|
||||
}
|
||||
|
||||
// TODO make static
|
||||
u16 TrackReadU16(struct SNDTrack *track) {
|
||||
int retval;
|
||||
|
||||
retval = TrackReadU8(track);
|
||||
retval |= TrackReadU8(track) << 8;
|
||||
|
||||
return (u16)retval;
|
||||
}
|
||||
|
||||
static u32 TrackReadU24(struct SNDTrack *track) {
|
||||
u32 retval;
|
||||
|
||||
retval = TrackReadU8(track);
|
||||
retval |= TrackReadU8(track) << 8;
|
||||
retval |= TrackReadU8(track) << 16;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int TrackReadVLV(struct SNDTrack *track) {
|
||||
int retval = 0;
|
||||
int b;
|
||||
|
||||
do {
|
||||
b = TrackReadU8(track);
|
||||
retval = (retval << 7) | (b & 0x7F);
|
||||
} while(b & 0x80);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int TrackParseValue(struct SNDTrack *track, struct SNDPlayer *player, int valueType) {
|
||||
int retval;
|
||||
int hi;
|
||||
int lo;
|
||||
int ran;
|
||||
s16 *var;
|
||||
|
||||
// BUG: undefined behavior if invalid valueType is passed (uninitialized return value)
|
||||
|
||||
switch (valueType) {
|
||||
case SND_SEQ_VAL_U8:
|
||||
retval = TrackReadU8(track);
|
||||
break;
|
||||
case SND_SEQ_VAL_U16:
|
||||
retval = TrackReadU16(track);
|
||||
break;
|
||||
case SND_SEQ_VAL_VLV:
|
||||
retval = TrackReadVLV(track);
|
||||
break;
|
||||
case SND_SEQ_VAL_VAR:
|
||||
var = PlayerGetVariablePointer(player, TrackReadU8(track));
|
||||
if (var)
|
||||
retval = *var;
|
||||
break;
|
||||
case SND_SEQ_VAL_RAN:
|
||||
lo = TrackReadU16(track) << 16;
|
||||
hi = (s16)TrackReadU16(track);
|
||||
ran = SND_CalcRandom();
|
||||
retval = hi - (lo >> 16);
|
||||
retval += 1;
|
||||
retval = (ran * retval) >> 16;
|
||||
retval += lo >> 16;
|
||||
break;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
// TODO make static
|
||||
void TrackInit(struct SNDTrack *track) {
|
||||
track->base = NULL;
|
||||
track->cur = NULL;
|
||||
|
||||
track->flags.noteWait = TRUE;
|
||||
track->flags.muted = FALSE;
|
||||
track->flags.tie = FALSE;
|
||||
track->flags.noteFinishWait = FALSE;
|
||||
track->flags.portamento = FALSE;
|
||||
track->flags.cmp = TRUE;
|
||||
track->flags.channelMask = FALSE;
|
||||
|
||||
track->callStackDepth = 0;
|
||||
track->program = 0;
|
||||
track->priority = 64;
|
||||
track->volume = 127;
|
||||
track->expression = 127;
|
||||
track->extFader = 0;
|
||||
track->pan = 0;
|
||||
track->extPan = 0;
|
||||
track->pitchBend = 0;
|
||||
track->extPitch = 0;
|
||||
track->envAttack = 255;
|
||||
track->envDecay = 255;
|
||||
track->envSustain = 255;
|
||||
track->envRelease = 255;
|
||||
track->panRange = 127;
|
||||
track->bendRange = 2;
|
||||
track->portamentoKey = 60;
|
||||
track->portamentoTime = 0;
|
||||
track->sweepPitch = 0;
|
||||
track->transpose = 0;
|
||||
track->channelMask = 0xFFFF;
|
||||
SND_InitLfoParam(&track->mod);
|
||||
track->wait = 0;
|
||||
track->channelLLHead = NULL;
|
||||
}
|
||||
|
||||
// TODO make static
|
||||
void TrackStart(struct SNDTrack *track, const void *seq, u32 offset) {
|
||||
track->base = (const u8 *)seq;
|
||||
track->cur = &track->base[offset];
|
||||
}
|
||||
|
||||
// TODO make static later
|
||||
void PlayerInit(struct SNDPlayer *player, struct SNDBankData *bank) {
|
||||
player->flags.paused = FALSE;
|
||||
player->bank = bank;
|
||||
player->tempo = 120;
|
||||
player->tempoRatio = 256;
|
||||
player->tempoCounter = SND_TIMER_RATE;
|
||||
player->volume = 0x7F;
|
||||
player->extFader = 0;
|
||||
player->prio = 64;
|
||||
|
||||
for (int i = 0; i < SND_TRACK_COUNT_PER_PLAYER; i++) {
|
||||
player->tracks[i] = 0xFF;
|
||||
}
|
||||
|
||||
if (SNDi_SharedWork) {
|
||||
SNDi_SharedWork->players[player->playerId].tickCounter = 0;
|
||||
|
||||
for (int i = 0; i < SND_TRACK_COUNT_PER_PLAYER; i++) {
|
||||
SNDi_SharedWork->players[player->playerId].localVars[i] = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO make static
|
||||
void TrackReleaseChannels(struct SNDTrack *track, struct SNDPlayer *player, int release) {
|
||||
TrackUpdateChannel(track, player, 0);
|
||||
|
||||
for (struct SNDExChannel *chn = track->channelLLHead; chn; chn = chn->channelLLNext) {
|
||||
if (SND_IsExChannelActive(chn)) {
|
||||
if (release >= 0)
|
||||
SND_SetExChannelRelease(chn, release & 0xFF);
|
||||
chn->priority = 1;
|
||||
SND_ReleaseExChannel(chn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO make static
|
||||
void TrackFreeChannels(struct SNDTrack *track) {
|
||||
for (struct SNDExChannel *chn = track->channelLLHead; chn; chn = chn->channelLLNext) {
|
||||
SND_FreeExChannel(chn);
|
||||
}
|
||||
|
||||
track->channelLLHead = NULL;
|
||||
}
|
||||
|
||||
void PlayerSeqMain(struct SNDPlayer *player) {
|
||||
int ticks = 0;
|
||||
int tempoInc;
|
||||
int i;
|
||||
|
||||
while (player->tempoCounter >= SND_TIMER_RATE) {
|
||||
player->tempoCounter -= SND_TIMER_RATE;
|
||||
ticks++;
|
||||
}
|
||||
|
||||
for (i = 0; i < ticks; i++) {
|
||||
if (PlayerStepTicks(player, SND_PROC_PLAY_NOTES)) {
|
||||
PlayerStop(player);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (SNDi_SharedWork) {
|
||||
SNDi_SharedWork->players[player->playerId].tickCounter += i;
|
||||
}
|
||||
|
||||
tempoInc = player->tempo;
|
||||
tempoInc *= player->tempoRatio;
|
||||
tempoInc >>= 8;
|
||||
|
||||
player->tempoCounter += tempoInc;
|
||||
}
|
||||
|
||||
struct SNDTrack *PlayerGetTrack(struct SNDPlayer *player, int track) {
|
||||
if (track > (SND_TRACK_COUNT_PER_PLAYER - 1))
|
||||
return NULL;
|
||||
|
||||
if (player->tracks[track] == 0xFF)
|
||||
return NULL;
|
||||
|
||||
return &SNDi_Work.tracks[player->tracks[track]];
|
||||
}
|
||||
|
||||
static void TrackStop(struct SNDTrack *track, struct SNDPlayer *player) {
|
||||
TrackReleaseChannels(track, player, -1);
|
||||
TrackFreeChannels(track);
|
||||
}
|
||||
|
||||
static void PlayerStopTrack(struct SNDPlayer *player, int trackIdx) {
|
||||
struct SNDTrack *track = PlayerGetTrack(player, trackIdx);
|
||||
|
||||
if (track == NULL)
|
||||
return;
|
||||
|
||||
TrackStop(track, player);
|
||||
SNDi_Work.tracks[player->tracks[trackIdx]].flags.active = FALSE;
|
||||
player->tracks[trackIdx] = 0xFF;
|
||||
}
|
||||
|
||||
void PlayerStop(struct SNDPlayer *player) {
|
||||
for (int i = 0; i < SND_TRACK_COUNT_PER_PLAYER; i++) {
|
||||
PlayerStopTrack(player, i);
|
||||
}
|
||||
player->flags.active = FALSE;
|
||||
}
|
||||
|
||||
static void ChannelCallback(struct SNDExChannel *chn, int status, void *track_) {
|
||||
struct SNDExChannel *cur;
|
||||
struct SNDTrack *track;
|
||||
|
||||
track = (struct SNDTrack *)track_;
|
||||
|
||||
if (status == 1) {
|
||||
chn->priority = 0;
|
||||
SND_FreeExChannel(chn);
|
||||
}
|
||||
|
||||
if (track->channelLLHead == chn) {
|
||||
track->channelLLHead = chn->channelLLNext;
|
||||
} else {
|
||||
cur = track->channelLLHead;
|
||||
|
||||
while (cur->channelLLNext) {
|
||||
if (cur->channelLLNext == chn) {
|
||||
cur->channelLLNext = chn->channelLLNext;
|
||||
return;
|
||||
}
|
||||
cur = cur->channelLLNext;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void TrackUpdateChannel(struct SNDTrack *track, struct SNDPlayer *player, int release) {
|
||||
int vol;
|
||||
int fader;
|
||||
int pan;
|
||||
int pitch;
|
||||
|
||||
vol = SNDi_DecibelSquareTable[track->volume] +
|
||||
SNDi_DecibelSquareTable[track->expression] +
|
||||
SNDi_DecibelSquareTable[player->volume];
|
||||
|
||||
fader = track->extFader + player->extFader;
|
||||
|
||||
pitch = track->pitchBend;
|
||||
pitch *= track->bendRange << 6;
|
||||
pitch >>= 7;
|
||||
pitch += track->extPitch;
|
||||
|
||||
pan = track->pan;
|
||||
|
||||
if (track->panRange != 127)
|
||||
pan = (pan * track->panRange + 0x40) >> 7;
|
||||
|
||||
pan += track->extPan;
|
||||
|
||||
if (vol < -0x8000)
|
||||
vol = -0x8000;
|
||||
|
||||
if (fader < -0x8000)
|
||||
fader = -0x8000;
|
||||
|
||||
if (pan < -128)
|
||||
pan = -128;
|
||||
else if (pan > 127)
|
||||
pan = 127;
|
||||
|
||||
for (struct SNDExChannel *chn = track->channelLLHead; chn != NULL; chn = chn->channelLLNext) {
|
||||
chn->userDecay2 = (short)fader;
|
||||
|
||||
if (chn->envStatus == 3)
|
||||
continue;
|
||||
|
||||
chn->userDecay = (s16)vol;
|
||||
chn->userPitch = (s16)pitch;
|
||||
chn->userPan = (s8)pan;
|
||||
chn->panRange = track->panRange;
|
||||
chn->lfo.param = track->mod;
|
||||
|
||||
if (chn->length == 0 && release != 0) {
|
||||
chn->priority = 1;
|
||||
SND_ReleaseExChannel(chn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO make static
|
||||
void PlayerUpdateChannel(struct SNDPlayer *player) {
|
||||
for (int i = 0; i < SND_TRACK_COUNT_PER_PLAYER; i++) {
|
||||
struct SNDTrack *trk = PlayerGetTrack(player, i);
|
||||
if (trk) {
|
||||
TrackUpdateChannel(trk, player, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void TrackPlayNote(struct SNDTrack *track, struct SNDPlayer *player, int midiKey, int velocity, int length) {
|
||||
struct SNDExChannel *chn = NULL;
|
||||
|
||||
if (track->flags.tie) {
|
||||
chn = track->channelLLHead;
|
||||
if (chn) {
|
||||
chn->midiKey = (u8)midiKey;
|
||||
chn->velocity = (u8)velocity;
|
||||
}
|
||||
}
|
||||
|
||||
if (chn == NULL) {
|
||||
struct SNDInstData inst;
|
||||
if (!SND_ReadInstData(player->bank, track->program, midiKey, &inst))
|
||||
return;
|
||||
|
||||
u32 allowedChannels;
|
||||
|
||||
switch (inst.type) {
|
||||
case SND_INST_PCM:
|
||||
case SND_INST_DIRECTPCM:
|
||||
// all channels support PCM
|
||||
allowedChannels = 0xFFFF;
|
||||
break;
|
||||
case SND_INST_PSG:
|
||||
// only channels 8, 9, 10, 11, 12, 13 support PSG
|
||||
allowedChannels = 0x3F00;
|
||||
break;
|
||||
case SND_INST_NOISE:
|
||||
// only channels 14 and 15 support noise
|
||||
allowedChannels = 0xC000;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
allowedChannels &= track->channelMask;
|
||||
|
||||
chn = SND_AllocExChannel(allowedChannels, player->prio + track->priority, track->flags.channelMask, ChannelCallback, track);
|
||||
if (chn == NULL)
|
||||
return;
|
||||
|
||||
if (!SND_NoteOn(chn, midiKey, velocity, track->flags.tie ? -1 : length, player->bank, &inst)) {
|
||||
chn->priority = 0;
|
||||
SND_FreeExChannel(chn);
|
||||
return;
|
||||
}
|
||||
|
||||
chn->channelLLNext = track->channelLLHead;
|
||||
track->channelLLHead = chn;
|
||||
}
|
||||
|
||||
if (track->envAttack != 0xFF)
|
||||
SND_SetExChannelAttack(chn, track->envAttack);
|
||||
|
||||
if (track->envDecay != 0xFF)
|
||||
SND_SetExChannelDecay(chn, track->envDecay);
|
||||
|
||||
if (track->envSustain != 0xFF)
|
||||
SND_SetExChannelSustain(chn, track->envSustain);
|
||||
|
||||
if (track->envRelease != 0xFF)
|
||||
SND_SetExChannelRelease(chn, track->envRelease);
|
||||
|
||||
chn->sweepPitch = track->sweepPitch;
|
||||
if (track->flags.portamento)
|
||||
chn->sweepPitch += (short)((track->portamentoKey - midiKey) << 6);
|
||||
|
||||
if (track->portamentoTime == 0) {
|
||||
chn->sweepLength = length;
|
||||
chn->flags.autoSweep = FALSE;
|
||||
} else {
|
||||
int swp = track->portamentoTime * track->portamentoTime;
|
||||
swp *= chn->sweepPitch < 0 ? -chn->sweepPitch : chn->sweepPitch;
|
||||
swp >>= 11;
|
||||
chn->sweepLength = swp;
|
||||
}
|
||||
|
||||
chn->sweepCounter = 0;
|
||||
}
|
||||
|
||||
static int TrackStepTicks(struct SNDTrack *track, struct SNDPlayer *player, int trackIdx, u32 playNotes) {
|
||||
(void)trackIdx;
|
||||
|
||||
struct SNDExChannel *chn;
|
||||
u8 cmd;
|
||||
enum SNDSeqVal valueType;
|
||||
BOOL specialValueType;
|
||||
BOOL runCmd;
|
||||
s32 length;
|
||||
int midiKey;
|
||||
|
||||
s32 par;
|
||||
|
||||
|
||||
for (chn = track->channelLLHead; chn; chn = chn->channelLLNext) {
|
||||
if (chn->length > 0)
|
||||
chn->length--;
|
||||
|
||||
if (!chn->flags.autoSweep && chn->sweepCounter < chn->sweepLength)
|
||||
chn->sweepCounter++;
|
||||
}
|
||||
|
||||
if (track->flags.noteFinishWait) {
|
||||
if (track->channelLLHead)
|
||||
return 0;
|
||||
track->flags.noteFinishWait = FALSE;
|
||||
}
|
||||
|
||||
if (track->wait > 0) {
|
||||
track->wait--;
|
||||
if (track->wait > 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
SeqCacheFetch(track->cur);
|
||||
|
||||
while (track->wait == 0 && !track->flags.noteFinishWait) {
|
||||
specialValueType = FALSE;
|
||||
runCmd = TRUE;
|
||||
|
||||
cmd = TrackReadU8(track);
|
||||
|
||||
if (cmd == 0xA2) {
|
||||
cmd = TrackReadU8(track);
|
||||
runCmd = track->flags.cmp;
|
||||
}
|
||||
|
||||
if (cmd == 0xA0) {
|
||||
cmd = TrackReadU8(track);
|
||||
valueType = SND_SEQ_VAL_RAN;
|
||||
specialValueType = TRUE;
|
||||
}
|
||||
|
||||
if (cmd == 0xA1) {
|
||||
cmd = TrackReadU8(track);
|
||||
valueType = SND_SEQ_VAL_VAR;
|
||||
specialValueType = TRUE;
|
||||
}
|
||||
|
||||
if ((cmd & 0x80) == 0) {
|
||||
par = TrackReadU8(track);
|
||||
|
||||
length = TrackParseValue(track, player, specialValueType ? valueType : SND_SEQ_VAL_VLV);
|
||||
midiKey = cmd + track->transpose;
|
||||
|
||||
if (!runCmd)
|
||||
continue;
|
||||
|
||||
if (midiKey < 0)
|
||||
midiKey = 0;
|
||||
else if (midiKey > 127) {
|
||||
midiKey = 127;
|
||||
}
|
||||
|
||||
if (!track->flags.muted && playNotes != 0) {
|
||||
TrackPlayNote(track, player, midiKey, par, (length > 0) ? length : -1);
|
||||
}
|
||||
|
||||
track->portamentoKey = (u8)midiKey;
|
||||
|
||||
if (track->flags.noteWait) {
|
||||
track->wait = length;
|
||||
if (length == 0) {
|
||||
track->flags.noteFinishWait = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (cmd & 0xF0) {
|
||||
case 0x80:
|
||||
par = TrackParseValue(track, player, specialValueType ? valueType : SND_SEQ_VAL_VLV);
|
||||
if (!runCmd)
|
||||
break;
|
||||
|
||||
switch (cmd) {
|
||||
case 0x80:
|
||||
track->wait = par;
|
||||
break;
|
||||
case 0x81:
|
||||
if (par < 0x10000)
|
||||
track->program = (u16)par;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x90:
|
||||
switch (cmd) {
|
||||
case 0x93:
|
||||
{
|
||||
u32 off;
|
||||
struct SNDTrack *newTrack;
|
||||
|
||||
par = TrackReadU8(track);
|
||||
off = TrackReadU24(track);
|
||||
if (!runCmd)
|
||||
break;
|
||||
|
||||
newTrack = PlayerGetTrack(player, par);
|
||||
if (newTrack && newTrack != track) {
|
||||
TrackStop(newTrack, player);
|
||||
TrackStart(newTrack, track->base, off);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x94:
|
||||
{
|
||||
u32 off = TrackReadU24(track);
|
||||
if (!runCmd)
|
||||
break;
|
||||
track->cur = &track->base[off];
|
||||
}
|
||||
break;
|
||||
case 0x95:
|
||||
{
|
||||
u32 off = TrackReadU24(track);
|
||||
if (!runCmd)
|
||||
break;
|
||||
|
||||
if (track->callStackDepth < SND_TRACK_MAX_CALL) {
|
||||
track->posCallStack[track->callStackDepth] = track->cur;
|
||||
track->callStackDepth++;
|
||||
track->cur = &track->base[off];
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0xC0:
|
||||
case 0xD0:
|
||||
{
|
||||
union {
|
||||
u8 _u8;
|
||||
s8 _s8;
|
||||
} par;
|
||||
par._u8 = (u8)TrackParseValue(track, player, specialValueType ? valueType : SND_SEQ_VAL_U8);
|
||||
if (!runCmd)
|
||||
break;
|
||||
|
||||
switch (cmd) {
|
||||
case 0xC1:
|
||||
track->volume = par._u8;
|
||||
break;
|
||||
case 0xD5:
|
||||
track->expression = par._u8;
|
||||
break;
|
||||
case 0xC2:
|
||||
player->volume = par._u8;
|
||||
break;
|
||||
case 0xC5:
|
||||
track->bendRange = par._u8;
|
||||
break;
|
||||
case 0xC6:
|
||||
track->priority = par._u8;
|
||||
break;
|
||||
case 0xC7:
|
||||
track->flags.noteWait = par._u8;
|
||||
break;
|
||||
case 0xCF:
|
||||
track->portamentoTime = par._u8;
|
||||
break;
|
||||
case 0xCA:
|
||||
track->mod.depth = par._u8;
|
||||
break;
|
||||
case 0xCB:
|
||||
track->mod.speed = par._u8;
|
||||
break;
|
||||
case 0xCC:
|
||||
track->mod.target = par._u8;
|
||||
break;
|
||||
case 0xCD:
|
||||
track->mod.range = par._u8;
|
||||
break;
|
||||
case 0xD0:
|
||||
track->envAttack = par._u8;
|
||||
break;
|
||||
case 0xD1:
|
||||
track->envDecay = par._u8;
|
||||
break;
|
||||
case 0xD2:
|
||||
track->envSustain = par._u8;
|
||||
break;
|
||||
case 0xD3:
|
||||
track->envRelease = par._u8;
|
||||
break;
|
||||
case 0xD4:
|
||||
if (track->callStackDepth < SND_TRACK_MAX_CALL) {
|
||||
track->posCallStack[track->callStackDepth] = track->cur;
|
||||
track->loopCount[track->callStackDepth] = par._u8;
|
||||
track->callStackDepth++;
|
||||
}
|
||||
break;
|
||||
case 0xC8:
|
||||
track->flags.tie = par._u8;
|
||||
TrackReleaseChannels(track, player, -1);
|
||||
TrackFreeChannels(track);
|
||||
break;
|
||||
case 0xD7:
|
||||
TrackMute(track, player, par._u8);
|
||||
break;
|
||||
case 0xC9:
|
||||
track->portamentoKey = (u8)(par._u8 + track->transpose);
|
||||
track->flags.portamento = TRUE;
|
||||
break;
|
||||
case 0xCE:
|
||||
track->flags.portamento = par._u8;
|
||||
break;
|
||||
case 0xC3:
|
||||
track->transpose = par._s8;
|
||||
break;
|
||||
case 0xC4:
|
||||
track->pitchBend = par._s8;
|
||||
break;
|
||||
case 0xC0:
|
||||
track->pan = (s8)(par._u8 - 0x40);
|
||||
break;
|
||||
case 0xD6:
|
||||
{
|
||||
s16 *varPtr;
|
||||
|
||||
if (sPrintEnabled) {
|
||||
varPtr = PlayerGetVariablePointer(player, par._u8);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0xE0:
|
||||
{
|
||||
s16 par = (s16)TrackParseValue(track, player, specialValueType ? valueType : SND_SEQ_VAL_U16);
|
||||
if (!runCmd)
|
||||
break;
|
||||
|
||||
switch (cmd) {
|
||||
case 0xE3:
|
||||
track->sweepPitch = par;
|
||||
break;
|
||||
case 0xE1:
|
||||
player->tempo = (u16)par;
|
||||
break;
|
||||
case 0xE0:
|
||||
track->mod.delay = (u16)par;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0xB0:
|
||||
{
|
||||
// TODO fix refalloc -> stack on varNum
|
||||
int varNum = TrackReadU8(track);
|
||||
|
||||
s16 par = (s16)TrackParseValue(track, player, specialValueType ? valueType : SND_SEQ_VAL_U16);
|
||||
s16 *varPtr = PlayerGetVariablePointer(player, varNum);
|
||||
|
||||
if (!runCmd)
|
||||
break;
|
||||
|
||||
if (varPtr == NULL)
|
||||
break;
|
||||
|
||||
switch (cmd) {
|
||||
case 0xB0:
|
||||
*varPtr = par;
|
||||
break;
|
||||
case 0xB1:
|
||||
*varPtr += par;
|
||||
break;
|
||||
case 0xB2:
|
||||
*varPtr -= par;
|
||||
break;
|
||||
case 0xB3:
|
||||
*varPtr *= par;
|
||||
break;
|
||||
case 0xB4:
|
||||
if (par != 0)
|
||||
*varPtr /= par;
|
||||
break;
|
||||
case 0xB5:
|
||||
if (par >= 0)
|
||||
*varPtr <<= par;
|
||||
else
|
||||
*varPtr >>= -par;
|
||||
break;
|
||||
case 0xB6:
|
||||
{
|
||||
BOOL neg = FALSE;
|
||||
if (par < 0) {
|
||||
neg = TRUE;
|
||||
par = (s16)(-par);
|
||||
}
|
||||
s32 random = SND_CalcRandom();
|
||||
random = (random * (par + 1)) >> 16;
|
||||
if (neg)
|
||||
random = -random;
|
||||
*varPtr = (s16)random;
|
||||
}
|
||||
break;
|
||||
case 0xB7:
|
||||
break;
|
||||
case 0xB8:
|
||||
track->flags.cmp = *varPtr == par;
|
||||
break;
|
||||
case 0xB9:
|
||||
track->flags.cmp = *varPtr >= par;
|
||||
break;
|
||||
case 0xBA:
|
||||
track->flags.cmp = *varPtr > par;
|
||||
break;
|
||||
case 0xBB:
|
||||
track->flags.cmp = *varPtr <= par;
|
||||
break;
|
||||
case 0xBC:
|
||||
track->flags.cmp = *varPtr < par;
|
||||
break;
|
||||
case 0xBD:
|
||||
track->flags.cmp = *varPtr != par;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0xF0:
|
||||
if (!runCmd)
|
||||
break;
|
||||
|
||||
switch (cmd) {
|
||||
case 0xFD:
|
||||
if (track->callStackDepth != 0) {
|
||||
track->callStackDepth--;
|
||||
track->cur = track->posCallStack[track->callStackDepth];
|
||||
}
|
||||
break;
|
||||
case 0xFC:
|
||||
{
|
||||
if (track->callStackDepth == 0)
|
||||
break;
|
||||
|
||||
// gosh, this was nasty to figure out
|
||||
u8 loopCount = track->loopCount[track->callStackDepth - 1];
|
||||
if (loopCount != 0) {
|
||||
loopCount--;
|
||||
if (loopCount == 0) {
|
||||
track->callStackDepth--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
track->loopCount[track->callStackDepth - 1] = loopCount;
|
||||
track->cur = track->posCallStack[track->callStackDepth - 1];
|
||||
}
|
||||
break;
|
||||
case 0xFE:
|
||||
break;
|
||||
case 0xFF:
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
BOOL PlayerStepTicks(struct SNDPlayer *player, u32 ticks) {
|
||||
BOOL isPlaying = FALSE;
|
||||
|
||||
for (int i = 0; i < SND_TRACK_COUNT_PER_PLAYER; i++) {
|
||||
struct SNDTrack *trk = PlayerGetTrack(player, i);
|
||||
|
||||
if (trk && trk->cur) {
|
||||
if (TrackStepTicks(trk, player, i, ticks))
|
||||
PlayerStopTrack(player, i);
|
||||
else
|
||||
isPlaying = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return !isPlaying;
|
||||
}
|
||||
|
||||
static s16 *PlayerGetVariablePointer(const struct SNDPlayer *player, int var) {
|
||||
if (SNDi_SharedWork == NULL)
|
||||
return NULL;
|
||||
else if (var < 16) {
|
||||
return &SNDi_SharedWork->players[player->playerId].localVars[var];
|
||||
} else {
|
||||
return &SNDi_SharedWork->globalVars[var - 16];
|
||||
}
|
||||
}
|
||||
|
||||
int AllocateTrack(void) {
|
||||
for (int i = 0; i < SND_TRACK_COUNT; i++) {
|
||||
if (!SNDi_Work.tracks[i].flags.active) {
|
||||
SNDi_Work.tracks[i].flags.active = TRUE;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// TODO make static after merging with SND_seq
|
||||
void TrackMute(struct SNDTrack *track, struct SNDPlayer *player, int muteMode) {
|
||||
switch (muteMode) {
|
||||
case SND_TRACK_MUTE_MODE_UNMUTE:
|
||||
track->flags.muted = FALSE;
|
||||
break;
|
||||
case SND_TRACK_MUTE_MODE_MUTE:
|
||||
track->flags.muted = TRUE;
|
||||
break;
|
||||
case SND_TRACK_MUTE_MODE_MUTE_RELEASE:
|
||||
track->flags.muted = TRUE;
|
||||
TrackReleaseChannels(track, player, -1);
|
||||
break;
|
||||
case SND_TRACK_MUTE_MODE_MUTE_STOP:
|
||||
track->flags.muted = TRUE;
|
||||
TrackReleaseChannels(track, player, 127);
|
||||
TrackFreeChannels(track);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
#ifndef GUARD_SND_SEQ_SHARED_H
|
||||
#define GUARD_SND_SEQ_SHARED_H
|
||||
|
||||
#include "nitro/SND_exChannel_shared.h"
|
||||
|
||||
#define SND_TRACK_COUNT_PER_PLAYER 16
|
||||
#define SND_INVALID_TRACK_INDEX 0xFF
|
||||
|
||||
|
||||
Reference in New Issue
Block a user