mirror of
https://github.com/zeldaret/ss
synced 2026-07-03 20:40:09 -04:00
d_snd_bgm_mml_parser_base
This commit is contained in:
@@ -2700,10 +2700,12 @@ d/snd/d_snd_bgm_sound.cpp:
|
||||
|
||||
d/snd/d_snd_bgm_data_mgr.cpp:
|
||||
.text start:0x8037BA70 end:0x8037C518 align:16
|
||||
.data start:0x80549148 end:0x80549158
|
||||
.sdata start:0x805742F0 end:0x805742F8
|
||||
|
||||
d/snd/d_snd_bgm_mml_parser_base.cpp:
|
||||
.text start:0x8037C520 end:0x8037D014 align:16
|
||||
.data start:0x80549158 end:0x80549168
|
||||
|
||||
d/snd/d_snd_bgm_mml_parsers.cpp:
|
||||
.text start:0x8037D020 end:0x8037D800 align:16
|
||||
|
||||
+13
-13
@@ -20798,18 +20798,18 @@ fn_8037C370 = .text:0x8037C370; // type:function size:0x34
|
||||
fn_8037C3B0 = .text:0x8037C3B0; // type:function size:0x58
|
||||
fn_8037C410 = .text:0x8037C410; // type:function size:0x60
|
||||
setHarpPitchSeqVars = .text:0x8037C470; // type:function size:0xA8
|
||||
fn_8037C520 = .text:0x8037C520; // type:function size:0x20
|
||||
fn_8037C540 = .text:0x8037C540; // type:function size:0x34
|
||||
fn_8037C580 = .text:0x8037C580; // type:function size:0x98
|
||||
fn_8037C620 = .text:0x8037C620; // type:function size:0x1E0
|
||||
dSndMmlParser__Parse = .text:0x8037C800; // type:function size:0x4F0
|
||||
dSndMmlParser__CommandProc = .text:0x8037CCF0; // type:function size:0x18C
|
||||
dSndMmlParser__Read16 = .text:0x8037CE80; // type:function size:0x24
|
||||
dSndMmlParser__Read24 = .text:0x8037CEB0; // type:function size:0x38
|
||||
dSndMmlParser__ReadVar = .text:0x8037CEF0; // type:function size:0x30
|
||||
dSndMmlParser__ReadArg = .text:0x8037CF20; // type:function size:0xD8
|
||||
fn_8037D000 = .text:0x8037D000; // type:function size:0x4
|
||||
fn_8037D010 = .text:0x8037D010; // type:function size:0x4
|
||||
__ct__18dSndBgmMmlParser_cFPQ34nw4r3snd18SoundArchivePlayerPQ34nw4r3snd12SoundArchive = .text:0x8037C520; // type:function size:0x20
|
||||
initTrack__18dSndBgmMmlParser_cFlUl = .text:0x8037C540; // type:function size:0x34
|
||||
loadAndParse__18dSndBgmMmlParser_cFUlUlb = .text:0x8037C580; // type:function size:0x98
|
||||
readTracks__18dSndBgmMmlParser_cFUlUlb = .text:0x8037C620; // type:function size:0x1E0
|
||||
Parse__18dSndBgmMmlParser_cCFP12dBgmMmlTrack = .text:0x8037C800; // type:function size:0x4F0
|
||||
CommandProc___18dSndBgmMmlParser_cCFP12dBgmMmlTrackUlll = .text:0x8037CCF0; // type:function size:0x18C
|
||||
Read16__18dSndBgmMmlParser_cCFPPCUc = .text:0x8037CE80; // type:function size:0x24
|
||||
Read24__18dSndBgmMmlParser_cCFPPCUc = .text:0x8037CEB0; // type:function size:0x38
|
||||
ReadVar__18dSndBgmMmlParser_cCFPPCUc = .text:0x8037CEF0; // type:function size:0x30
|
||||
ReadArg__18dSndBgmMmlParser_cCFPPCUcQ218dSndBgmMmlParser_c10SeqArgType = .text:0x8037CF20; // type:function size:0xD8
|
||||
CommandProc__18dSndBgmMmlParser_cCFUliUlll = .text:0x8037D000; // type:function size:0x4
|
||||
NoteOnCommandProc__18dSndBgmMmlParser_cCFUliiil = .text:0x8037D010; // type:function size:0x4
|
||||
fn_8037D020 = .text:0x8037D020; // type:function size:0x64
|
||||
fn_8037D090 = .text:0x8037D090; // type:function size:0xE8
|
||||
fn_8037D180 = .text:0x8037D180; // type:function size:0x84
|
||||
@@ -38042,7 +38042,7 @@ lbl_80549088 = .data:0x80549088; // type:object size:0x34
|
||||
lbl_805490BC = .data:0x805490BC; // type:object size:0x44
|
||||
lbl_80549100 = .data:0x80549100; // type:object size:0x48
|
||||
lbl_80549148 = .data:0x80549148; // type:object size:0x10
|
||||
lbl_80549158 = .data:0x80549158; // type:object size:0x10
|
||||
__vt__18dSndBgmMmlParser_c = .data:0x80549158; // type:object size:0x10
|
||||
lbl_80549168 = .data:0x80549168; // type:object size:0x10
|
||||
lbl_80549178 = .data:0x80549178; // type:object size:0x10
|
||||
lbl_80549188 = .data:0x80549188; // type:object size:0x10
|
||||
|
||||
+1
-1
@@ -758,7 +758,7 @@ config.libs = [
|
||||
Object(NonMatching, "d/snd/d_snd_bgm_sound_battle_callbacks.cpp"),
|
||||
Object(NonMatching, "d/snd/d_snd_bgm_sound.cpp"),
|
||||
Object(NonMatching, "d/snd/d_snd_bgm_data_mgr.cpp"),
|
||||
Object(NonMatching, "d/snd/d_snd_bgm_mml_parser_base.cpp"),
|
||||
Object(Matching, "d/snd/d_snd_bgm_mml_parser_base.cpp"),
|
||||
Object(NonMatching, "d/snd/d_snd_bgm_mml_parsers.cpp"),
|
||||
Object(NonMatching, "d/snd/d_snd_small_effect_mgr.cpp"),
|
||||
Object(NonMatching, "d/snd/d_snd_harp_mgr.cpp"),
|
||||
|
||||
@@ -0,0 +1,203 @@
|
||||
#ifndef D_SND_BGM_MML_PARSER_BASE_H
|
||||
#define D_SND_BGM_MML_PARSER_BASE_H
|
||||
|
||||
#include "common.h"
|
||||
#include "nw4r/snd/snd_SoundArchive.h"
|
||||
#include "nw4r/snd/snd_SoundArchivePlayer.h"
|
||||
|
||||
// [R89JEL]:/bin/RVL/Debug/mainD.elf:.debug::0x2cdd6
|
||||
struct dBgmMmlCallStack
|
||||
{
|
||||
bool loopFlag; // size 0x01, offset 0x00
|
||||
u8 loopCount; // size 0x01, offset 0x01
|
||||
/* 2 bytes padding */
|
||||
byte_t const *address; // size 0x04, offset 0x04
|
||||
}; // size 0x08
|
||||
|
||||
/**
|
||||
* Size: 0x28
|
||||
*/
|
||||
struct dBgmMmlTrack {
|
||||
/* 0x00 */ const byte_t *currentAddr;
|
||||
/* 0x04 */ u8 mTrackNo;
|
||||
/* 0x05 */ bool mTrackUsed;
|
||||
/* 0x06 */ u8 cmpFlag;
|
||||
/* 0x08 */ s32 wait;
|
||||
/* 0x0C */ dBgmMmlCallStack callStack[3];
|
||||
/* 0x24 */ s32 callStackDepth;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Parses harp key data
|
||||
*
|
||||
* Partial copy of nw4r::snd::detail::MmlParser
|
||||
*/
|
||||
class dSndBgmMmlParser_c {
|
||||
private:
|
||||
// [R89JEL]:/bin/RVL/Debug/mainD.elf:.debug::0x2d70c
|
||||
// Swapped - or maybe just returns a boolean
|
||||
enum ParseResult {
|
||||
PARSE_RESULT_FINISH,
|
||||
PARSE_RESULT_CONTINUE,
|
||||
};
|
||||
|
||||
// [R89JEL]:/bin/RVL/Debug/mainD.elf:.debug::0x31279
|
||||
enum SeqArgType {
|
||||
SEQ_ARG_NONE,
|
||||
|
||||
SEQ_ARG_U8,
|
||||
SEQ_ARG_S16,
|
||||
SEQ_ARG_VMIDI,
|
||||
SEQ_ARG_RANDOM,
|
||||
SEQ_ARG_VARIABLE,
|
||||
};
|
||||
|
||||
enum MmlCommand {
|
||||
MML_CMD_MIN = 0x80, // <80 -> MML note, not a command
|
||||
MML_CMD_MAX = 0xff,
|
||||
|
||||
MML_CMD_MASK = 0x80,
|
||||
MML_CMD_SET_MASK = 0xf0,
|
||||
|
||||
MML_WAIT = 0x80,
|
||||
MML_SET_PRGNO,
|
||||
|
||||
MML_OPEN_TRACK = 0x88,
|
||||
MML_JUMP,
|
||||
MML_CALL,
|
||||
|
||||
MML_ARG_1_RANDOM = 0xa0,
|
||||
MML_ARG_1_VARIABLE,
|
||||
MML_EXEC_IF,
|
||||
MML_ARG_2_S16,
|
||||
MML_ARG_2_RANDOM,
|
||||
MML_ARG_2_VARIABLE,
|
||||
|
||||
MML_SET_TIMEBASE = 0xb0,
|
||||
MML_SET_ENV_HOLD,
|
||||
MML_SET_MONOPHONIC,
|
||||
MML_SET_TRACK_VELOCITY_RANGE,
|
||||
MML_SET_BIQUAD_TYPE,
|
||||
MML_SET_BIQUAD_VALUE,
|
||||
|
||||
MML_SET_PAN = 0xc0,
|
||||
MML_SET_TRACK_VOLUME,
|
||||
MML_SET_PLAYER_VOLUME,
|
||||
MML_SET_TRANSPOSE,
|
||||
MML_SET_PITCH_BEND,
|
||||
MML_SET_BEND_RANGE,
|
||||
MML_SET_PRIORITY,
|
||||
MML_SET_NOTE_WAIT,
|
||||
MML_SET_TIE,
|
||||
MML_SET_PORTAMENTO,
|
||||
MML_SET_LFO_DEPTH,
|
||||
MML_SET_LFO_SPEED,
|
||||
MML_SET_LFO_TARGET,
|
||||
MML_SET_LFO_RANGE,
|
||||
MML_SET_PORTASPEED,
|
||||
MML_SET_PORTATIME,
|
||||
|
||||
MML_SET_ATTACK = 0xd0,
|
||||
MML_SET_DECAY,
|
||||
MML_SET_SUSTAIN,
|
||||
MML_SET_RELEASE,
|
||||
MML_LOOP_START,
|
||||
MML_SET_TRACK_VOLUME2,
|
||||
MML_PRINT_VAR,
|
||||
MML_SET_SURROUND_PAN,
|
||||
MML_SET_LPF_FREQ,
|
||||
MML_SET_FX_SEND_A,
|
||||
MML_SET_FX_SEND_B,
|
||||
MML_SET_MAIN_SEND,
|
||||
MML_SET_INIT_PAN,
|
||||
MML_SET_MUTE,
|
||||
MML_SET_FX_SEND_C,
|
||||
MML_SET_DAMPER,
|
||||
|
||||
MML_SET_LFO_DELAY = 0xe0,
|
||||
MML_SET_TEMPO,
|
||||
MML_SET_E2,
|
||||
MML_SET_SWEEP_PITCH,
|
||||
|
||||
MML_RESET_ADSR = 0xfb,
|
||||
MML_LOOP_END,
|
||||
MML_RET,
|
||||
MML_ALLOC_TRACK,
|
||||
MML_EOF
|
||||
};
|
||||
|
||||
enum MmlExCommand {
|
||||
MML_EX_COMMAND = 0xf0,
|
||||
|
||||
MML_EX_CMD_MAX = 0xffff,
|
||||
|
||||
MML_EX_ARITHMETIC = 0x80,
|
||||
MML_EX_SET = 0x80,
|
||||
MML_EX_APL,
|
||||
MML_EX_AMI,
|
||||
MML_EX_AMU,
|
||||
MML_EX_ADV,
|
||||
MML_EX_ALS,
|
||||
MML_EX_RND,
|
||||
MML_EX_AAD,
|
||||
MML_EX_AOR,
|
||||
MML_EX_AER,
|
||||
MML_EX_ACO,
|
||||
MML_EX_AMD,
|
||||
|
||||
MML_EX_LOGIC = 0x90,
|
||||
MML_EX_EQ = 0x90,
|
||||
MML_EX_GE,
|
||||
MML_EX_GT,
|
||||
MML_EX_LE,
|
||||
MML_EX_LT,
|
||||
MML_EX_NE,
|
||||
|
||||
MML_EX_USERPROC = 0xe0,
|
||||
};
|
||||
|
||||
public:
|
||||
dSndBgmMmlParser_c(nw4r::snd::SoundArchivePlayer *player, nw4r::snd::SoundArchive *archive);
|
||||
|
||||
virtual void CommandProc(u32 trackNo, int wait, u32 command, s32 commandArg1, s32 commandArg2) const;
|
||||
virtual void NoteOnCommandProc(u32 trackNo, int wait, int key, int velocity, s32 length) const;
|
||||
|
||||
protected:
|
||||
bool loadAndParse(u32 soundId, u32 trackMask, bool noJumps);
|
||||
|
||||
private:
|
||||
bool readTracks(u32 soundId, u32 trackMask, bool noJumps);
|
||||
void initTrack(s32 trackNo, u32 offset);
|
||||
ParseResult Parse(dBgmMmlTrack *track) const;
|
||||
void CommandProc_(dBgmMmlTrack *track, u32 command, s32 commandArg1, s32 commandArg2) const;
|
||||
|
||||
u8 ReadByte(byte_t const **ptr) const {
|
||||
return *(*ptr)++;
|
||||
}
|
||||
u16 Read16(byte_t const **ptr) const;
|
||||
u32 Read24(byte_t const **ptr) const;
|
||||
s32 ReadVar(byte_t const **ptr) const;
|
||||
s32 ReadArg(byte_t const **ptr, SeqArgType argType) const;
|
||||
|
||||
// static members
|
||||
public:
|
||||
static int const TEMPO_MAX = 1023;
|
||||
static int const TEMPO_MIN = 0;
|
||||
static int const CALL_STACK_DEPTH = 3;
|
||||
static int const SURROUND_PAN_CENTER;
|
||||
static int const PAN_CENTER = 64;
|
||||
|
||||
private:
|
||||
static bool mPrintVarEnabledFlag;
|
||||
|
||||
// members
|
||||
private:
|
||||
/* vtable */ // size 0x04, offset 0x00
|
||||
/* 0x04 */ u8 field_0x04;
|
||||
/* 0x08 */ nw4r::snd::SoundArchivePlayer *mpPlayer;
|
||||
/* 0x0C */ nw4r::snd::SoundArchive *mpArchive;
|
||||
/* 0x10 */ const byte_t *baseAddr;
|
||||
/* 0x14 */ dBgmMmlTrack mTracks[16];
|
||||
}; // size 0x04
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,580 @@
|
||||
#include "d/snd/d_snd_bgm_mml_parser_base.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "nw4r/snd/snd_SeqFile.h"
|
||||
#include "nw4r/snd/snd_SoundArchive.h"
|
||||
#include "nw4r/snd/snd_SoundArchivePlayer.h"
|
||||
|
||||
dSndBgmMmlParser_c::dSndBgmMmlParser_c(nw4r::snd::SoundArchivePlayer *player, nw4r::snd::SoundArchive *archive)
|
||||
: field_0x04(0), mpPlayer(player), mpArchive(archive) {}
|
||||
|
||||
void dSndBgmMmlParser_c::initTrack(s32 trackNo, u32 offset) {
|
||||
dBgmMmlTrack &trackParam = mTracks[trackNo];
|
||||
trackParam.currentAddr = baseAddr + offset;
|
||||
trackParam.mTrackNo = trackNo;
|
||||
trackParam.mTrackUsed = true;
|
||||
trackParam.cmpFlag = 0;
|
||||
trackParam.wait = 0;
|
||||
trackParam.callStackDepth = 0;
|
||||
}
|
||||
|
||||
bool dSndBgmMmlParser_c::loadAndParse(u32 soundId, u32 trackMask, bool noJumps) {
|
||||
if (!readTracks(soundId, trackMask, noJumps)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if (mTracks[i].mTrackUsed) {
|
||||
while (Parse(&mTracks[i]) != PARSE_RESULT_FINISH) {}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool dSndBgmMmlParser_c::readTracks(u32 soundId, u32 trackMask, bool noJumps) {
|
||||
nw4r::snd::SoundArchivePlayer *player = mpPlayer;
|
||||
nw4r::snd::SoundArchive *archive = mpArchive;
|
||||
|
||||
field_0x04 = noJumps;
|
||||
nw4r::snd::SoundArchive::SoundInfo info;
|
||||
if (!archive->ReadSoundInfo(soundId, &info)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (archive->GetSoundType(soundId) != nw4r::snd::SoundArchive::SOUND_TYPE_SEQ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const void *addr = player->detail_GetFileAddress(info.fileId);
|
||||
if (addr == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nw4r::snd::detail::SeqFileReader reader(addr);
|
||||
baseAddr = (const byte_t *)reader.GetBaseAddress();
|
||||
for (int i = 0; i < 16; i++) {
|
||||
mTracks[i].mTrackUsed = false;
|
||||
}
|
||||
initTrack(0, 0);
|
||||
|
||||
const byte_t *ptr = baseAddr;
|
||||
bool endReached = false;
|
||||
|
||||
for (int i = 0; i < 20; i++) {
|
||||
u32 cmd = ReadByte(&ptr);
|
||||
switch (cmd) {
|
||||
case MML_ALLOC_TRACK:
|
||||
Read16(&ptr);
|
||||
break;
|
||||
case MML_OPEN_TRACK: {
|
||||
u8 trackNo = ReadByte(&ptr);
|
||||
u32 offset = Read24(&ptr);
|
||||
if (((trackMask >> trackNo) & 1) != 0) {
|
||||
initTrack(trackNo, offset);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MML_SET_TIMEBASE:
|
||||
ptr += 1;
|
||||
break;
|
||||
default:
|
||||
endReached = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (endReached) {
|
||||
mTracks[0].currentAddr = ptr - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!endReached) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((trackMask & 1) == 0) {
|
||||
mTracks[0].mTrackUsed = false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
|
||||
// modified from nw4r::snd - some changes I had to make to make it match might be fake
|
||||
dSndBgmMmlParser_c::ParseResult dSndBgmMmlParser_c::Parse(dBgmMmlTrack *track) const {
|
||||
dBgmMmlTrack &trackParam = *track;
|
||||
|
||||
// Had to move these up for regswaps - maybe fake
|
||||
s32 commandArg1;
|
||||
s32 commandArg2;
|
||||
|
||||
SeqArgType argType;
|
||||
SeqArgType argType2 = SEQ_ARG_NONE;
|
||||
|
||||
bool useArgType = false;
|
||||
bool doExecCommand = true;
|
||||
|
||||
|
||||
u32 cmd = ReadByte(&trackParam.currentAddr);
|
||||
|
||||
if (cmd == MML_EXEC_IF)
|
||||
{
|
||||
cmd = ReadByte(&trackParam.currentAddr);
|
||||
doExecCommand = trackParam.cmpFlag != false;
|
||||
}
|
||||
|
||||
if (cmd == MML_ARG_2_S16)
|
||||
{
|
||||
cmd = ReadByte(&trackParam.currentAddr);
|
||||
argType2 = SEQ_ARG_S16;
|
||||
}
|
||||
else if (cmd == MML_ARG_2_RANDOM)
|
||||
{
|
||||
cmd = ReadByte(&trackParam.currentAddr);
|
||||
argType2 = SEQ_ARG_RANDOM;
|
||||
}
|
||||
else if (cmd == MML_ARG_2_VARIABLE)
|
||||
{
|
||||
cmd = ReadByte(&trackParam.currentAddr);
|
||||
argType2 = SEQ_ARG_VARIABLE;
|
||||
}
|
||||
|
||||
if (cmd == MML_ARG_1_RANDOM)
|
||||
{
|
||||
cmd = ReadByte(&trackParam.currentAddr);
|
||||
argType = SEQ_ARG_RANDOM;
|
||||
useArgType = true;
|
||||
}
|
||||
else if (cmd == MML_ARG_1_VARIABLE)
|
||||
{
|
||||
cmd = ReadByte(&trackParam.currentAddr);
|
||||
argType = SEQ_ARG_VARIABLE;
|
||||
useArgType = true;
|
||||
}
|
||||
|
||||
if (!(cmd & MML_CMD_MASK))
|
||||
{
|
||||
// MML note data, not a command
|
||||
u8 velocity = ReadByte(&trackParam.currentAddr);
|
||||
|
||||
s32 length = ReadArg(&trackParam.currentAddr,
|
||||
useArgType ? argType : SEQ_ARG_VMIDI);
|
||||
|
||||
if (!doExecCommand)
|
||||
return PARSE_RESULT_CONTINUE;
|
||||
|
||||
int key = cmd;
|
||||
|
||||
NoteOnCommandProc(trackParam.mTrackNo, trackParam.wait, key, velocity,
|
||||
length > 0 ? length : -1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// MML command
|
||||
commandArg1 = 0;
|
||||
commandArg2 = 0;
|
||||
|
||||
switch (cmd & MML_CMD_SET_MASK)
|
||||
{
|
||||
case 0x80:
|
||||
{
|
||||
switch (cmd)
|
||||
{
|
||||
case MML_WAIT:
|
||||
{
|
||||
s32 arg = ReadArg(&trackParam.currentAddr,
|
||||
useArgType ? argType : SEQ_ARG_VMIDI);
|
||||
|
||||
if (doExecCommand)
|
||||
trackParam.wait += arg;
|
||||
}
|
||||
break;
|
||||
|
||||
case MML_SET_PRGNO:
|
||||
commandArg1 = ReadArg(&trackParam.currentAddr,
|
||||
useArgType ? argType : SEQ_ARG_VMIDI);
|
||||
|
||||
if (doExecCommand)
|
||||
CommandProc_(track, cmd, commandArg1, commandArg2);
|
||||
|
||||
break;
|
||||
|
||||
case MML_OPEN_TRACK:
|
||||
{
|
||||
// Had to change u8 -> u32 for regswaps - maybe fake
|
||||
u32 trackNo = ReadByte(&trackParam.currentAddr);
|
||||
u32 offset = Read24(&trackParam.currentAddr);
|
||||
|
||||
if (doExecCommand)
|
||||
{
|
||||
commandArg1 = trackNo;
|
||||
commandArg2 = offset;
|
||||
CommandProc_(track, cmd, commandArg1, commandArg2);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case MML_JUMP:
|
||||
case MML_CALL:
|
||||
{
|
||||
u32 offset = Read24(&trackParam.currentAddr);
|
||||
|
||||
if (doExecCommand)
|
||||
{
|
||||
commandArg1 = offset;
|
||||
CommandProc_(track, cmd, commandArg1, commandArg2);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xb0:
|
||||
case 0xc0:
|
||||
case 0xd0:
|
||||
{
|
||||
u8 arg = ReadArg(&trackParam.currentAddr,
|
||||
useArgType ? argType : SEQ_ARG_U8);
|
||||
|
||||
if (argType2 != SEQ_ARG_NONE)
|
||||
{
|
||||
commandArg2 =
|
||||
ReadArg(&trackParam.currentAddr, argType2);
|
||||
}
|
||||
|
||||
if (!doExecCommand)
|
||||
break;
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
case MML_SET_TRANSPOSE:
|
||||
case MML_SET_PITCH_BEND:
|
||||
commandArg1 = *reinterpret_cast<s8 *>(&arg);
|
||||
break;
|
||||
|
||||
default:
|
||||
commandArg1 = *reinterpret_cast<u8 *>(&arg);
|
||||
break;
|
||||
}
|
||||
|
||||
CommandProc_(track, cmd, commandArg1, commandArg2);
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x90:
|
||||
if (doExecCommand)
|
||||
CommandProc_(track, cmd, commandArg1, commandArg2);
|
||||
|
||||
break;
|
||||
|
||||
case 0xe0:
|
||||
commandArg1 =
|
||||
static_cast<s16>(ReadArg(&trackParam.currentAddr,
|
||||
useArgType ? argType : SEQ_ARG_S16));
|
||||
|
||||
if (doExecCommand)
|
||||
CommandProc_(track, cmd, commandArg1, commandArg2);
|
||||
|
||||
break;
|
||||
|
||||
case 0xf0:
|
||||
{
|
||||
switch (cmd)
|
||||
{
|
||||
case MML_ALLOC_TRACK:
|
||||
Read16(&trackParam.currentAddr);
|
||||
NW4RPanicMessage_Line(
|
||||
312, "seq: must use alloctrack in startup code");
|
||||
|
||||
break;
|
||||
|
||||
case MML_EOF:
|
||||
if (doExecCommand)
|
||||
return PARSE_RESULT_FINISH;
|
||||
|
||||
break;
|
||||
|
||||
case MML_EX_COMMAND:
|
||||
{
|
||||
u32 cmdex = ReadByte(&trackParam.currentAddr);
|
||||
|
||||
switch (cmdex & MML_CMD_SET_MASK)
|
||||
{
|
||||
case MML_EX_USERPROC:
|
||||
commandArg1 = static_cast<u16>(
|
||||
ReadArg(&trackParam.currentAddr,
|
||||
useArgType ? argType : SEQ_ARG_S16));
|
||||
|
||||
if (doExecCommand)
|
||||
{
|
||||
CommandProc_(track, (cmd << 8) + cmdex, commandArg1,
|
||||
commandArg2);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case MML_EX_ARITHMETIC:
|
||||
case MML_EX_LOGIC:
|
||||
commandArg1 = ReadByte(&trackParam.currentAddr);
|
||||
commandArg2 = static_cast<s16>(
|
||||
ReadArg(&trackParam.currentAddr,
|
||||
useArgType ? argType : SEQ_ARG_S16));
|
||||
|
||||
if (doExecCommand)
|
||||
{
|
||||
CommandProc_(track, (cmd << 8) + cmdex, commandArg1,
|
||||
commandArg2);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
ATTR_FALLTHROUGH;
|
||||
|
||||
default:
|
||||
if (doExecCommand)
|
||||
CommandProc_(track, cmd, commandArg1, commandArg2);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xa0:
|
||||
NW4RPanicMessage_Line(392, "Invalid seqdata command: %d", cmd);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return PARSE_RESULT_CONTINUE;
|
||||
}
|
||||
|
||||
// very stripped down from nw4r::snd
|
||||
void dSndBgmMmlParser_c::CommandProc_(dBgmMmlTrack *track, u32 command, s32 commandArg1, s32 commandArg2) const {
|
||||
dBgmMmlTrack &trackParam = *track;
|
||||
|
||||
switch (command)
|
||||
{
|
||||
case MML_JUMP:
|
||||
if (field_0x04 == 0)
|
||||
trackParam.currentAddr = baseAddr + commandArg1;
|
||||
break;
|
||||
|
||||
case MML_CALL:
|
||||
{
|
||||
if (trackParam.callStackDepth >= CALL_STACK_DEPTH)
|
||||
{
|
||||
NW4RWarningMessage_Line(665,
|
||||
"nw4r::snd::MmlParser: cannot \'call\' "
|
||||
"because already too deep");
|
||||
break;
|
||||
}
|
||||
|
||||
dBgmMmlCallStack *callStack =
|
||||
&trackParam.callStack[trackParam.callStackDepth];
|
||||
|
||||
callStack->address = trackParam.currentAddr;
|
||||
callStack->loopFlag = false;
|
||||
|
||||
trackParam.callStackDepth++;
|
||||
trackParam.currentAddr = baseAddr + commandArg1;
|
||||
break;
|
||||
}
|
||||
|
||||
case MML_RET:
|
||||
{
|
||||
dBgmMmlCallStack *tmp; // needed for lbzu
|
||||
dBgmMmlCallStack *callStack = nullptr;
|
||||
|
||||
while (trackParam.callStackDepth > 0)
|
||||
{
|
||||
tmp = &trackParam.callStack[--trackParam.callStackDepth];
|
||||
|
||||
if (!tmp->loopFlag)
|
||||
{
|
||||
callStack = tmp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!callStack)
|
||||
{
|
||||
NW4RWarningMessage_Line(
|
||||
688,
|
||||
"nw4r::snd::MmlParser: unmatched sequence command \'ret\'");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
trackParam.currentAddr = callStack->address;
|
||||
}
|
||||
break;
|
||||
|
||||
case MML_LOOP_START:
|
||||
{
|
||||
if (trackParam.callStackDepth >= CALL_STACK_DEPTH)
|
||||
{
|
||||
NW4RWarningMessage_Line(
|
||||
698, "nw4r::snd::MmlParser: cannot \'loop_start\' because "
|
||||
"already too deep");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
dBgmMmlCallStack *callStack =
|
||||
&trackParam.callStack[trackParam.callStackDepth];
|
||||
|
||||
callStack->address = trackParam.currentAddr;
|
||||
callStack->loopFlag = true;
|
||||
callStack->loopCount = commandArg1;
|
||||
|
||||
trackParam.callStackDepth++;
|
||||
}
|
||||
break;
|
||||
|
||||
case MML_LOOP_END:
|
||||
{
|
||||
if (trackParam.callStackDepth <= 0)
|
||||
{
|
||||
NW4RWarningMessage_Line(713, "nw4r::snd::MmlParser: unmatched "
|
||||
"sequence command \'loop_end\'");
|
||||
break;
|
||||
}
|
||||
|
||||
dBgmMmlCallStack *callStack =
|
||||
&trackParam.callStack[trackParam.callStackDepth - 1];
|
||||
|
||||
if (!callStack->loopFlag)
|
||||
{
|
||||
NW4RWarningMessage_Line(719, "nw4r::snd::MmlParser: unmatched "
|
||||
"sequence command \'loop_end\'");
|
||||
break;
|
||||
}
|
||||
|
||||
u8 loop_count = callStack->loopCount;
|
||||
|
||||
if (loop_count && --loop_count == 0)
|
||||
{
|
||||
trackParam.callStackDepth--;
|
||||
}
|
||||
else
|
||||
{
|
||||
callStack->loopCount = loop_count;
|
||||
|
||||
trackParam.currentAddr = callStack->address;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
CommandProc(track->mTrackNo, track->wait, command, commandArg1, commandArg2);
|
||||
}
|
||||
|
||||
// copied from nw4r::snd start
|
||||
u16 dSndBgmMmlParser_c::Read16(byte_t const **ptr) const
|
||||
{
|
||||
u16 ret = ReadByte(ptr);
|
||||
|
||||
ret <<= 8;
|
||||
ret |= ReadByte(ptr);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
u32 dSndBgmMmlParser_c::Read24(byte_t const **ptr) const
|
||||
{
|
||||
u32 ret = ReadByte(ptr);
|
||||
|
||||
ret <<= 8;
|
||||
ret |= ReadByte(ptr);
|
||||
|
||||
ret <<= 8;
|
||||
ret |= ReadByte(ptr);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
s32 dSndBgmMmlParser_c::ReadVar(byte_t const **ptr) const
|
||||
{
|
||||
s32 ret = 0;
|
||||
byte_t b;
|
||||
|
||||
for (int i = 0;; i++)
|
||||
{
|
||||
NW4RAssert_Line(940, i < 4);
|
||||
|
||||
b = ReadByte(ptr);
|
||||
ret <<= 7;
|
||||
ret |= b & 0x7f;
|
||||
|
||||
if (!(b & 0x80))
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
s32 dSndBgmMmlParser_c::ReadArg(byte_t const **ptr,
|
||||
SeqArgType argType) const
|
||||
{
|
||||
s32 var;
|
||||
|
||||
switch (argType)
|
||||
{
|
||||
case SEQ_ARG_U8:
|
||||
var = ReadByte(ptr);
|
||||
break;
|
||||
|
||||
case SEQ_ARG_S16:
|
||||
var = Read16(ptr);
|
||||
break;
|
||||
|
||||
case SEQ_ARG_VMIDI:
|
||||
var = ReadVar(ptr);
|
||||
break;
|
||||
|
||||
case SEQ_ARG_VARIABLE:
|
||||
{
|
||||
var = ReadByte(ptr);
|
||||
/*
|
||||
u8 varNo = ReadByte(ptr);
|
||||
|
||||
s16 const volatile *varPtr = GetVariablePtr(player, track, varNo);
|
||||
|
||||
// ERRATUM: if varPtr is not valid then ReadArg returns garbage
|
||||
if (varPtr)
|
||||
var = *varPtr;
|
||||
*/
|
||||
}
|
||||
break;
|
||||
|
||||
case SEQ_ARG_RANDOM:
|
||||
{
|
||||
s32 rand;
|
||||
|
||||
s16 min = Read16(ptr);
|
||||
s16 max = Read16(ptr);
|
||||
|
||||
rand = nw4r::snd::detail::Util::CalcRandom();
|
||||
rand *= max - min + 1;
|
||||
rand >>= 16;
|
||||
rand += min;
|
||||
|
||||
var = rand;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return var;
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
void dSndBgmMmlParser_c::CommandProc(u32 trackNo, int wait, u32 command, s32 commandArg1, s32 commandArg2) const {
|
||||
// noop
|
||||
}
|
||||
|
||||
void dSndBgmMmlParser_c::NoteOnCommandProc(u32 trackNo, int wait, int key, int velocity, s32 length) const {
|
||||
// noop
|
||||
}
|
||||
Reference in New Issue
Block a user