summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Panzlaff <michael.panzlaff@fau.de>2021-08-01 03:00:03 +0200
committerMichael Panzlaff <michael.panzlaff@fau.de>2021-08-25 18:03:49 +0200
commit80b1041da789f4c83318287ca59c5f95ae84fb6a (patch)
tree29ab6f1afa163aa89f26a5eb9007e158bf5f00ae
parentc2bd97bebcecbe1d1743572ea99fa82fb9019832 (diff)
arm7: merge SND_seq SND_unk
-rw-r--r--arm7/arm7.lsf1
-rw-r--r--arm7/lib/include/SND_unk_037FD440.h25
-rw-r--r--arm7/lib/src/SND_seq.c905
-rw-r--r--arm7/lib/src/SND_unk_037FD440.c904
4 files changed, 904 insertions, 931 deletions
diff --git a/arm7/arm7.lsf b/arm7/arm7.lsf
index 4c14fd1e..074e5311 100644
--- a/arm7/arm7.lsf
+++ b/arm7/arm7.lsf
@@ -49,7 +49,6 @@ Autoload WRAM
Object SND_wave.o
Object SND_lockChannel.o
Object SND_exChannel.o
- Object SND_unk_037FD440.o
Object SND_seq.o
Object SND_bank.o
Object SND_work.o
diff --git a/arm7/lib/include/SND_unk_037FD440.h b/arm7/lib/include/SND_unk_037FD440.h
deleted file mode 100644
index f73825c8..00000000
--- a/arm7/lib/include/SND_unk_037FD440.h
+++ /dev/null
@@ -1,25 +0,0 @@
-#ifndef GUARD_SND_UNK_H
-#define GUARD_SND_UNK_H
-
-#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 PlayerInit(struct SNDPlayer *player, struct SNDBankData *bankData);
-int AllocateTrack(void);
-void TrackInit(struct SNDTrack *track);
-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 PlayerUpdateChannel(struct SNDPlayer *player);
-
-#endif //GUARD_SND_UNK_H
diff --git a/arm7/lib/src/SND_seq.c b/arm7/lib/src/SND_seq.c
index 65ec9d6a..76664fdd 100644
--- a/arm7/lib/src/SND_seq.c
+++ b/arm7/lib/src/SND_seq.c
@@ -2,7 +2,58 @@
#include "SND_main.h"
#include "SND_work.h"
-#include "SND_unk_037FD440.h"
+#include "SND_util.h"
+#include "SND_lfo.h"
+#include "SND_exChannel.h"
+#include "SND_bank.h"
+
+#define SND_TIMER_RATE 240
+
+#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,
+};
+
+static struct {
+ const u8 *begin;
+ const u8 *end;
+ union {
+ u8 buf[16];
+ u32 buf32[4];
+ };
+} sSeqCache;
+static int sPrintEnabled;
+
+static void PlayerSeqMain(struct SNDPlayer *player);
+static void PlayerUpdateChannel(struct SNDPlayer *player);
+static void PlayerStop(struct SNDPlayer *player);
+static void PlayerInit(struct SNDPlayer *player, struct SNDBankData *bank);
+static int AllocateTrack(void);
+static void TrackInit(struct SNDTrack *track);
+static void TrackStart(struct SNDTrack *track, const void *seq, u32 offset);
+static void SeqCacheFetch(const u8 *addr);
+static u8 SeqReadByte(const u8 *addr);
+static u16 TrackReadU16(struct SNDTrack *track);
+static struct SNDTrack *PlayerGetTrack(struct SNDPlayer *player, int track);
+static void TrackReleaseChannels(struct SNDTrack *track, struct SNDPlayer *player, int release);
+static void TrackFreeChannels(struct SNDTrack *track);
+static BOOL PlayerStepTicks(struct SNDPlayer *player, u32 ticks);
+static void TrackMute(struct SNDTrack *track, struct SNDPlayer *player, int muteMode);
+static s16 *PlayerGetVariablePointer(const struct SNDPlayer *player, int var);
+static void TrackUpdateChannel(struct SNDTrack *track, struct SNDPlayer *player, int release);
void SND_SeqInit(void) {
for (int i = 0; i < SND_PLAYER_COUNT; i++) {
@@ -264,3 +315,855 @@ void SNDi_SetTrackParam(int player, u32 trackMask, u32 offset, u32 data, int siz
}
}
}
+
+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];
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+static void TrackStart(struct SNDTrack *track, const void *seq, u32 offset) {
+ track->base = (const u8 *)seq;
+ track->cur = &track->base[offset];
+}
+
+static 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;
+ }
+ }
+}
+
+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);
+ }
+ }
+}
+
+static void TrackFreeChannels(struct SNDTrack *track) {
+ for (struct SNDExChannel *chn = track->channelLLHead; chn; chn = chn->channelLLNext) {
+ SND_FreeExChannel(chn);
+ }
+
+ track->channelLLHead = NULL;
+}
+
+static 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;
+}
+
+static 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;
+}
+
+static 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);
+ }
+ }
+}
+
+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:
+ {
+ 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;
+}
+
+static 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];
+ }
+}
+
+static 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;
+}
+
+static 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;
+ }
+}
diff --git a/arm7/lib/src/SND_unk_037FD440.c b/arm7/lib/src/SND_unk_037FD440.c
deleted file mode 100644
index 253ccecb..00000000
--- a/arm7/lib/src/SND_unk_037FD440.c
+++ /dev/null
@@ -1,904 +0,0 @@
-#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;
- }
-}