#include "sys.h"
#include "sf64audio_provisional.h"
#include "context.h"
#include "audiothread_cmd.h"
#include "audioseq_cmd.h"

void func_8001D0B4(f32* sfxSource, u32 sfxId, f32 freqMod);
s32 Audio_GetCurrentVoice(void);
void Audio_PlaySequence(u8, u16, u8, u8);
void Audio_PlayFanfare(u16, u8, u8, u8);
void Audio_PlaySequenceDistorted(u8, u16, u16, u8, u8);

void func_8001DD40(void);
void func_8001D6DC(u8);
void func_8001DE1C(u8);

static const char devstr1[] = "preload start (%d): ";
static const char devstr2[] = "%d ";
static const char devstr3[] = "\n";
static const char devstr4[] = "***** START SEQ : %d *****\n";
static const char devstr5[] = "spec change finished !!!\n";
static const char devstr6[] = "interface wait spec change finished !!!\n";
static const char devstr7[] = "********** SE Interface Buffer SE Stop %08X **********\n";
static const char devstr8[] = "MedlayStart : \n";
static const char devstr9[] = "MedlayStart : \n";
static const char devstr10[] = "MedlayStart(TuneUp) : \n";
static const char devstr11[] = "MedlayStart(cross) : \n";
static const char devstr12[] = "MedlayEnd : \n";
static const char devstr13[] = "MedlayWait : %d\n";
static const char devstr14[] = "ControlSePicth : %f %f %f \n";
static const char devstr15[] = "ChangeWarningSePara : %d %d\n";
static const char devstr16[] = "set Grp 0 port %02x \n";
static const char devstr17[] = "main BGM start %08X\n";
static const char devstr18[] = "<<<<< PlayCrossMixBgm pass !!! >>>>>\n";
static const char devstr19[] = "SetVolumeBallnce %d %d\n";
static const char devstr20[] = "START HANDLE : %d (old:%d)\n";
static const char devstr21[] = "All Sound Fade Out time:%d\n";

SfxRequest sSfxRequests[256];
SfxBankEntry sSfxBanks[5][20];
u8 sSfxBankListEnd[5];
u8 sSfxBankFreeListStart[5];
u8 sSfxBankUnused[5];
ActiveSfx sActiveSfx[5][8];
u8 sCurSfxPlayerChannelIndex;
u8 sSfxBankMuted[5];
Modulation sSfxVolumeMods[5];
f32 D_80149AD8[256];
f32 D_80149ED8[256];
f32 D_8014A2D8[384];
f32 D_8014A8D8[32];
u8 D_8014A958[32];
SeqRequest sSeqRequests[4][5];
u8 sNumSeqRequests[4];
s32 sAudioSeqCmds[256];
ActiveSequence sActiveSequences[4];
u16 sDelayedSeqCmdFlags;
DelayedSeqCmd sDelayedSeqCmds[16];
SfxChannelState sSfxChannelState[16];
PlayerNoiseModulation sPlayerNoise[4];
f32 D_8014BA10[4];
u8 D_8014BA20[4];
u8 D_8014BA24[4];
s32 D_8014BA28[4];

u8 sChannelsPerBank[5][5] = {
    { 3, 2, 2, 2, 2 }, { 3, 1, 2, 2, 2 }, { 3, 2, 2, 2, 3 }, { 6, 0, 2, 0, 4 }, { 0, 0, 0, 0, 0 },
};
u8 sUsedChannelsPerBank[5][5] = {
    { 3, 2, 1, 2, 3 }, { 3, 2, 1, 1, 2 }, { 3, 2, 1, 1, 3 }, { 2, 0, 1, 0, 1 }, { 0, 0, 0, 0, 0 },
};
u8 sSfxRequestWriteIndex = 0;
u8 sSfxRequestReadIndex = 0;
u8 sSfxChannelLayout = 0;
u16 sChannelMuteFlags = 0;
f32 gDefaultSfxSource[3] = { 0.0f, 0.0f, 0.0f };
f32 gDefaultMod = 1.0f;
s32 D_800C5D38 = 0; // unused. perhaps a default pan?
s8 gDefaultReverb = 0;
s32 sAudioFrameCounter = 0;
u8 sSeqCmdWritePos = 0;
u8 sSeqCmdReadPos = 0;
u8 sStartSeqDisabled = 0;
u8 sSoundModeList[4] = { SOUNDMODE_STEREO, SOUNDMODE_HEADSET, SOUNDMODE_SURROUND, SOUNDMODE_MONO };
u8 sNewAudioSpecId = 0;
u8 D_800C5D58 = 0;
s32 D_800C5D5C = 0; // unused. file split?
s8 sBaseReverb = 0;
s8 sAudioSpecReverb = 0;
u8 sVolumeSettings[3] = { 99, 99, 99 };
u8 D_800C5D6C[29][7] = {
    { 0, 3, 4, 80, 12, 21, 255 },    { 17, 18, 15, 96, 20, 22, 255 }, { 0, 3, 5, 80, 16, 255, 0 },
    { 17, 18, 15, 96, 20, 22, 255 }, { 0, 3, 4, 80, 12, 21, 255 },    { 17, 18, 15, 96, 20, 22, 255 },
    { 0, 3, 4, 80, 12, 21, 255 },    { 17, 18, 15, 96, 20, 22, 255 }, { 0, 3, 4, 80, 12, 21, 255 },
    { 0, 3, 4, 80, 12, 21, 255 },    { 17, 18, 15, 96, 20, 22, 255 }, { 0, 3, 4, 80, 12, 21, 255 },
    { 17, 18, 95, 96, 41, 255, 0 },  { 17, 18, 15, 96, 20, 22, 255 }, { 0, 3, 5, 80, 16, 255, 0 },
    { 0, 3, 4, 80, 12, 21, 255 },    { 0, 3, 4, 80, 12, 21, 255 },    { 17, 18, 15, 96, 20, 22, 255 },
    { 0, 3, 4, 80, 12, 21, 255 },    { 0, 3, 4, 80, 12, 21, 255 },    { 0, 3, 4, 80, 12, 21, 255 },
    { 255, 0, 0, 0, 0, 0, 0 },       { 255, 0, 0, 0, 0, 0, 0 },       { 255, 0, 0, 0, 0, 0, 0 },
    { 255, 0, 0, 0, 0, 0, 0 },       { 255, 0, 0, 0, 0, 0, 0 },       { 255, 0, 0, 0, 0, 0, 0 },
    { 255, 0, 0, 0, 0, 0, 0 },       { 0, 3, 4, 80, 12, 21, 255 },
};
s8 D_800C5E38[29] = {
    10, 0, 25, 0, 25, 0, 10, 0, 10, 35, 0, 10, 40, 0, 25, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
u32 D_800C5E58[5] = { 20, 16, 10, 10, 20 };
s32 D_800C5E6C = 0; // unused. file split?
u8 D_800C5E70 = 0;
f32 sSfxFreqMod = 1.0f;
f32 sSfxVolMod = 1.0f; // never modified
u8 sPlaylistIndex = 255;
s32 sPlaylistTimer = 0;
u8 sPlaylistCmdIndex = 0;
u32 D_800C5E88[] = {
    0x1903000D, 0x1903000E, 0x19500015, 0x2903A021, 0x4900000C, 0x19122005, 0x1913204A, 0x2900306A,
    0x29034024, 0x2902306C, 0x19032056, 0x19030057, 0x19033058, 0x19030006, 0x29503032, 0x1903407D,
    0x4900402E, 0x19038072, 0x1903807E, 0x1903807F, 0x19038080, 0x11032081, 0x19031082,
};
SoundTestTrack sSoundTestTracks[] = {
    /*  0 */ { SEQ_ID_OPENING, 22, -1 },
    /*  1 */ { SEQ_ID_TITLE, 23, -1 },
    /*  2 */ { SEQ_ID_MENU, 23, -1 },
    /*  3 */ { SEQ_ID_WORLD_MAP, 280, -1 },
    /*  4 */ { SEQ_ID_CO_INTRO, 0, -1 },
    /*  5 */ { SEQ_ID_INTRO_44, 1, -1 },
    /*  6 */ { SEQ_ID_INTRO_45, 1, -1 },
    /*  7 */ { SEQ_ID_ME_INTRO, 1, -1 },
    /*  8 */ { SEQ_ID_INTRO_51, 8, -1 },
    /*  9 */ { SEQ_ID_CORNERIA | SEQ_FLAG, 0, -1 },
    /* 10 */ { SEQ_ID_METEO | SEQ_FLAG, 1, -1 },
    /* 11 */ { SEQ_ID_TITANIA | SEQ_FLAG, 2, -1 },
    /* 12 */ { SEQ_ID_SECTOR_X | SEQ_FLAG, 3, -1 },
    /* 13 */ { SEQ_ID_ZONESS | SEQ_FLAG, 4, -1 },
    /* 14 */ { SEQ_ID_AREA_6 | SEQ_FLAG, 5, -1 },
    /* 15 */ { SEQ_ID_VENOM_1 | SEQ_FLAG, 6, -1 },
    /* 16 */ { SEQ_ID_SECTOR_Y | SEQ_FLAG, 7, -1 },
    /* 17 */ { SEQ_ID_FORTUNA | SEQ_FLAG, 8, -1 },
    /* 18 */ { SEQ_ID_BOLSE | SEQ_FLAG, 10, -1 },
    /* 19 */ { SEQ_ID_KATINA | SEQ_FLAG, 11, -1 },
    /* 20 */ { SEQ_ID_AQUAS, 12, -1 },
    /* 21 */ { SEQ_ID_WARP_ZONE | SEQ_FLAG, 1, -1 },
    /* 22 */ { SEQ_ID_KATT, 13, -1 },
    /* 23 */ { SEQ_ID_BILL, 11, -1 },
    /* 24 */ { SEQ_ID_CO_BOSS_1 | SEQ_FLAG, 0, -1 },
    /* 25 */ { SEQ_ID_ME_BOSS | SEQ_FLAG, 1, 0 },
    /* 26 */ { SEQ_ID_ME_BOSS | SEQ_FLAG, 1, -1 },
    /* 27 */ { SEQ_ID_BOSS_RESUME | SEQ_FLAG, 7, -1 },
    /* 28 */ { SEQ_ID_BO_BOSS | SEQ_FLAG, 10, -1 },
    /* 29 */ { SEQ_ID_STAR_WOLF | SEQ_FLAG, 6, -1 },
    /* 30 */ { SEQ_ID_GOOD_END, 0, -1 },
    /* 31 */ { SEQ_ID_BAD_END, 0, -1 },
    /* 32 */ { SEQ_ID_DEATH, 0, -1 },
    /* 33 */ { SEQ_ID_GAME_OVER, 25, -1 },
    /* 34 */ { SEQ_ID_TRAINING | SEQ_FLAG, 28, -1 },
    /* 35 */ { SEQ_ID_VERSUS | SEQ_FLAG, 784, -1 },
    /* 36 */ { SEQ_ID_VS_HURRY | SEQ_FLAG, 785, -1 },
    /* 37 */ { SEQ_ID_VS_MENU, 23, -1 },
    /* 38 */ { SEQ_ID_TO_ANDROSS | SEQ_FLAG, 6, 0 },
    /* 39 */ { SEQ_ID_ANDROSS | SEQ_FLAG, 23, -1 },
    /* 40 */ { SEQ_ID_AND_BOSS | SEQ_FLAG, 6, 0 },
    /* 41 */ { SEQ_ID_AND_BOSS | SEQ_FLAG, 6, -1 },
    /* 42 */ { SEQ_ID_AND_BRAIN | SEQ_FLAG, 6, -1 },
    /* 43 */ { SEQ_ID_VE_CLEAR | SEQ_FLAG, 6, -1 },
    /* 44 */ { SEQ_ID_ENDING, 27, -1 },
};

PlaylistCmd sPlaylists[][100] = {
    {
        { 0, 0, SEQ_ID_CO_INTRO, 0, 255, 1620 },
        { 0, 0, SEQ_ID_CORNERIA | SEQ_FLAG, 0, 255, 2490 },
        { 1, 0, SEQ_ID_CORNERIA | SEQ_FLAG, 50, 255, 50 },
        { 0, 0, SEQ_ID_CO_BOSS_1 | SEQ_FLAG, 0, 255, 1600 },
        { 1, 0, SEQ_ID_CO_BOSS_1 | SEQ_FLAG, 1, 255, 50 },
        { 0, 0, SEQ_ID_GOOD_END, 0, 255, 1091 },
        { 1, 0, SEQ_ID_GOOD_END, 100, 255, 100 },
        { 0, 0, SEQ_ID_ME_INTRO, 0, 255, 838 },
        { 0, 0, SEQ_ID_METEO | SEQ_FLAG, 0, 255, 1584 },
        { 1, 0, SEQ_ID_METEO | SEQ_FLAG, 50, 255, 50 },
        { 0, 0, SEQ_ID_ME_BOSS | SEQ_FLAG, 0, 0, 1620 },
        { 1, 0, SEQ_ID_ME_BOSS | SEQ_FLAG, 1, 255, 50 },
        { 0, 0, SEQ_ID_BOSS_RESUME | SEQ_FLAG, 0, 255, 1620 },
        { 1, 0, SEQ_ID_BOSS_RESUME | SEQ_FLAG, 1, 255, 50 },
        { 0, 0, SEQ_ID_GOOD_END, 0, 255, 1091 },
        { 1, 0, SEQ_ID_GOOD_END, 100, 255, 100 },
        { 0, 0, SEQ_ID_INTRO_51, 0, 255, 241 },
        { 0, 0, SEQ_ID_FORTUNA | SEQ_FLAG, 0, 255, 1632 },
        { 1, 0, SEQ_ID_FORTUNA | SEQ_FLAG, 100, 255, 100 },
        { 0, 0, SEQ_ID_STAR_WOLF | SEQ_FLAG, 0, 255, 2120 },
        { 0, 0, SEQ_ID_FORTUNA | SEQ_FLAG, 0, 0, 450 },
        { 1, 0, SEQ_ID_FORTUNA | SEQ_FLAG, 50, 255, 200 },
        { 0, 0, SEQ_ID_BAD_END, 0, 255, 1604 },
        { 1, 0, SEQ_ID_BAD_END, 100, 255, 100 },
        { 0, 0, SEQ_ID_INTRO_44, 0, 255, 242 },
        { 0, 0, SEQ_ID_SECTOR_X | SEQ_FLAG, 0, 255, 2291 },
        { 1, 0, SEQ_ID_SECTOR_X | SEQ_FLAG, 50, 255, 100 },
        { 0, 0, SEQ_ID_SX_BOSS | SEQ_FLAG, 0, 255, 1600 },
        { 1, 0, SEQ_ID_SX_BOSS | SEQ_FLAG, 1, 255, 50 },
        { 2, 0, SEQ_ID_SX_BOSS | SEQ_FLAG, 0, 255, 1600 },
        { 1, 0, SEQ_ID_SX_BOSS | SEQ_FLAG, 1, 255, 50 },
        { 0, 0, SEQ_ID_GOOD_END, 0, 255, 1091 },
        { 1, 0, SEQ_ID_GOOD_END, 100, 255, 100 },
        { 0, 0, SEQ_ID_INTRO_45, 0, 255, 542 },
        { 0, 0, SEQ_ID_TITANIA | SEQ_FLAG, 0, 255, 1920 },
        { 1, 0, SEQ_ID_TITANIA | SEQ_FLAG, 50, 255, 50 },
        { 0, 0, SEQ_ID_TI_BOSS | SEQ_FLAG, 0, 255, 1600 },
        { 1, 0, SEQ_ID_TI_BOSS | SEQ_FLAG, 1, 255, 50 },
        { 0, 0, SEQ_ID_GOOD_END, 0, 255, 1091 },
        { 1, 0, SEQ_ID_GOOD_END, 100, 255, 100 },
        { 0, 0, SEQ_ID_INTRO_51, 0, 255, 241 },
        { 0, 0, SEQ_ID_BOLSE | SEQ_FLAG, 0, 255, 1177 },
        { 1, 0, SEQ_ID_BOLSE | SEQ_FLAG, 100, 255, 100 },
        { 0, 0, SEQ_ID_BO_BOSS | SEQ_FLAG, 0, 255, 1115 },
        { 1, 0, SEQ_ID_BO_BOSS | SEQ_FLAG, 50, 255, 50 },
        { 0, 0, SEQ_ID_STAR_WOLF | SEQ_FLAG, 0, 255, 2120 },
        { 1, 0, SEQ_ID_STAR_WOLF | SEQ_FLAG, 1, 255, 50 },
        { 0, 0, SEQ_ID_DEATH, 0, 255, 150 },
        { 0, 0, SEQ_ID_GAME_OVER, 0, 255, 1020 },
        { 1, 0, SEQ_ID_GAME_OVER, 100, 255, 100 },
        { 255, 0, SEQ_ID_CORNERIA | SEQ_FLAG, 50, 255, 50 },
    },
    {
        { 0, 0, SEQ_ID_CO_INTRO, 0, 255, 1620 },
        { 0, 0, SEQ_ID_CORNERIA | SEQ_FLAG, 0, 255, 2490 },
        { 1, 0, SEQ_ID_CORNERIA | SEQ_FLAG, 50, 255, 50 },
        { 0, 0, SEQ_ID_CO_BOSS_2 | SEQ_FLAG, 0, 255, 1620 },
        { 1, 0, SEQ_ID_CO_BOSS_2 | SEQ_FLAG, 1, 255, 50 },
        { 0, 0, SEQ_ID_GOOD_END, 0, 255, 1091 },
        { 1, 0, SEQ_ID_GOOD_END, 100, 255, 100 },
        { 0, 0, SEQ_ID_INTRO_44, 0, 255, 242 },
        { 0, 0, SEQ_ID_SECTOR_Y | SEQ_FLAG, 0, 255, 2096 },
        { 1, 0, SEQ_ID_SECTOR_Y | SEQ_FLAG, 50, 255, 50 },
        { 0, 0, SEQ_ID_SY_BOSS | SEQ_FLAG, 0, 2, 1600 },
        { 1, 0, SEQ_ID_SY_BOSS | SEQ_FLAG, 1, 255, 50 },
        { 0, 0, SEQ_ID_BOSS_RESUME | SEQ_FLAG, 0, 255, 1600 },
        { 1, 0, SEQ_ID_BOSS_RESUME | SEQ_FLAG, 1, 255, 50 },
        { 0, 0, SEQ_ID_GOOD_END, 0, 255, 1091 },
        { 1, 0, SEQ_ID_GOOD_END, 100, 255, 100 },
        { 0, 0, SEQ_ID_INTRO_51, 0, 255, 241 },
        { 0, 0, SEQ_ID_KATINA | SEQ_FLAG, 0, 255, 2184 },
        { 1, 0, SEQ_ID_KATINA | SEQ_FLAG, 1, 255, 100 },
        { 0, 0, SEQ_ID_KA_BOSS | SEQ_FLAG, 0, 1, 1115 },
        { 1, 0, SEQ_ID_KA_BOSS | SEQ_FLAG, 50, 255, 100 },
        { 0, 0, SEQ_ID_GOOD_END, 0, 255, 1091 },
        { 1, 0, SEQ_ID_GOOD_END, 100, 255, 100 },
        { 0, 0, SEQ_ID_INTRO_51, 0, 255, 250 },
        { 0, 0, SEQ_ID_SOLAR | SEQ_FLAG, 0, 255, 1096 },
        { 3, 0, SEQ_ID_BILL, 0, 255, 1000 },
        { 1, 0, SEQ_ID_SOLAR | SEQ_FLAG, 50, 255, 50 },
        { 0, 0, SEQ_ID_SO_BOSS | SEQ_FLAG, 0, 255, 1600 },
        { 1, 0, SEQ_ID_SO_BOSS | SEQ_FLAG, 1, 255, 50 },
        { 0, 0, SEQ_ID_GOOD_END, 0, 255, 1091 },
        { 1, 0, SEQ_ID_GOOD_END, 100, 255, 100 },
        { 0, 0, SEQ_ID_INTRO_44, 0, 255, 260 },
        { 0, 0, SEQ_ID_MACBETH | SEQ_FLAG, 0, 255, 1920 },
        { 1, 0, SEQ_ID_MACBETH | SEQ_FLAG, 50, 255, 50 },
        { 0, 0, SEQ_ID_MA_BOSS | SEQ_FLAG, 0, 255, 1600 },
        { 1, 0, SEQ_ID_MA_BOSS | SEQ_FLAG, 1, 255, 50 },
        { 0, 0, SEQ_ID_GOOD_END, 0, 255, 1091 },
        { 1, 0, SEQ_ID_GOOD_END, 100, 255, 100 },
        { 0, 0, SEQ_ID_INTRO_51, 0, 255, 241 },
        { 0, 0, SEQ_ID_BOLSE | SEQ_FLAG, 0, 255, 1177 },
        { 1, 0, SEQ_ID_BOLSE | SEQ_FLAG, 100, 255, 100 },
        { 0, 0, SEQ_ID_BO_BOSS | SEQ_FLAG, 0, 255, 1115 },
        { 1, 0, SEQ_ID_BO_BOSS | SEQ_FLAG, 50, 255, 50 },
        { 0, 0, SEQ_ID_STAR_WOLF | SEQ_FLAG, 0, 255, 2120 },
        { 1, 0, SEQ_ID_STAR_WOLF | SEQ_FLAG, 1, 255, 50 },
        { 0, 0, SEQ_ID_GOOD_END, 0, 255, 1091 },
        { 1, 0, SEQ_ID_GOOD_END, 100, 255, 100 },
        { 0, 0, SEQ_ID_VENOM_1 | SEQ_FLAG, 0, 255, 1671 },
        { 1, 0, SEQ_ID_VENOM_1 | SEQ_FLAG, 50, 255, 50 },
        { 0, 0, SEQ_ID_VE_BOSS | SEQ_FLAG, 0, 255, 1600 },
        { 1, 0, SEQ_ID_VE_BOSS | SEQ_FLAG, 1, 255, 50 },
        { 0, 0, SEQ_ID_TO_ANDROSS | SEQ_FLAG, 0, 0, 176 },
        { 0, 0, SEQ_ID_ANDROSS | SEQ_FLAG, 0, 255, 588 },
        { 0, 0, SEQ_ID_AND_BOSS | SEQ_FLAG, 0, 0, 2420 },
        { 1, 0, SEQ_ID_AND_BOSS | SEQ_FLAG, 10, 255, 50 },
        { 0, 0, SEQ_ID_AND_BOSS | SEQ_FLAG, 0, 255, 1200 },
        { 1, 0, SEQ_ID_AND_BOSS | SEQ_FLAG, 1, 255, 150 },
        { 0, 0, SEQ_ID_VE_CLEAR | SEQ_FLAG, 0, 255, 1091 },
        { 1, 0, SEQ_ID_VE_CLEAR | SEQ_FLAG, 80, 255, 160 },
        { 0, 0, SEQ_ID_ENDING, 0, 255, 9500 },
        { 255, 0, SEQ_ID_CORNERIA | SEQ_FLAG, 50, 255, 50 },
        { 0 },
        { 0 },
        { 0 },
        { 0 },
        { 0 },
        { 0 },
        { 0 },
        { 0 },
        { 0 },
        { 0 },
        { 0 },
        { 0 },
        { 0 },
        { 0 },
        { 0 },
        { 0 },
        { 0 },
        { 0 },
        { 0 },
        { 0 },
        { 0 },
        { 0 },
        { 0 },
        { 0 },
        { 0 },
        { 0 },
        { 0 },
        { 0 },
        { 0 },
        { 0 },
        { 0 },
        { 0 },
        { 0 },
        { 0 },
        { 0 },
        { 0 },
        { 0 },
        { 0 },
        { 0 },
    },
    {
        { 0, 0, SEQ_ID_CO_INTRO, 0, 255, 1620 },
        { 0, 0, SEQ_ID_CORNERIA | SEQ_FLAG, 0, 255, 2490 },
        { 1, 0, SEQ_ID_CORNERIA | SEQ_FLAG, 50, 255, 50 },
        { 0, 0, SEQ_ID_CO_BOSS_2 | SEQ_FLAG, 0, 255, 1620 },
        { 1, 0, SEQ_ID_CO_BOSS_2 | SEQ_FLAG, 1, 255, 50 },
        { 0, 0, SEQ_ID_GOOD_END, 0, 255, 1091 },
        { 1, 0, SEQ_ID_GOOD_END, 100, 255, 100 },
        { 0, 0, SEQ_ID_INTRO_44, 0, 255, 260 },
        { 0, 0, SEQ_ID_SECTOR_Y | SEQ_FLAG, 0, 255, 2096 },
        { 1, 0, SEQ_ID_SECTOR_Y | SEQ_FLAG, 50, 255, 50 },
        { 0, 0, SEQ_ID_SY_BOSS | SEQ_FLAG, 0, 2, 1590 },
        { 1, 0, SEQ_ID_SY_BOSS | SEQ_FLAG, 1, 255, 50 },
        { 0, 0, SEQ_ID_BOSS_RESUME | SEQ_FLAG, 0, 255, 1600 },
        { 1, 0, SEQ_ID_BOSS_RESUME | SEQ_FLAG, 1, 255, 50 },
        { 0, 0, SEQ_ID_GOOD_END, 0, 255, 1091 },
        { 1, 0, SEQ_ID_GOOD_END, 100, 255, 100 },
        { 0, 0, SEQ_ID_INTRO_44, 0, 255, 260 },
        { 0, 0, SEQ_ID_AQUAS, 0, 255, 2400 },
        { 1, 0, SEQ_ID_AQUAS, 150, 255, 200 },
        { 0, 0, SEQ_ID_AQ_BOSS | SEQ_FLAG, 0, 1, 1590 },
        { 1, 0, SEQ_ID_AQ_BOSS | SEQ_FLAG, 1, 255, 50 },
        { 0, 0, SEQ_ID_GOOD_END, 0, 255, 1091 },
        { 1, 0, SEQ_ID_GOOD_END, 100, 255, 100 },
        { 0, 0, SEQ_ID_INTRO_44, 0, 255, 260 },
        { 0, 0, SEQ_ID_ZONESS | SEQ_FLAG, 0, 255, 1005 },
        { 3, 0, SEQ_ID_KATT, 0, 255, 1000 },
        { 1, 0, SEQ_ID_ZONESS | SEQ_FLAG, 50, 255, 100 },
        { 0, 0, SEQ_ID_ZO_BOSS | SEQ_FLAG, 0, 255, 1600 },
        { 1, 0, SEQ_ID_ZO_BOSS | SEQ_FLAG, 1, 255, 50 },
        { 0, 0, SEQ_ID_GOOD_END, 0, 255, 1091 },
        { 1, 0, SEQ_ID_GOOD_END, 100, 255, 100 },
        { 0, 0, SEQ_ID_INTRO_51, 0, 255, 241 },
        { 0, 0, SEQ_ID_SECTOR_Z | SEQ_FLAG, 0, 255, 1632 },
        { 1, 0, SEQ_ID_SECTOR_Z | SEQ_FLAG, 50, 255, 100 },
        { 0, 0, SEQ_ID_SZ_BOSS | SEQ_FLAG, 0, 1, 1310 },
        { 3, 0, SEQ_ID_KATT, 0, 255, 500 },
        { 1, 0, SEQ_ID_SZ_BOSS | SEQ_FLAG, 1, 255, 50 },
        { 0, 0, SEQ_ID_GOOD_END, 0, 255, 1091 },
        { 1, 0, SEQ_ID_GOOD_END, 100, 255, 100 },
        { 0, 0, SEQ_ID_INTRO_51, 0, 255, 241 },
        { 0, 0, SEQ_ID_AREA_6 | SEQ_FLAG, 0, 255, 1906 },
        { 1, 0, SEQ_ID_AREA_6 | SEQ_FLAG, 50, 255, 100 },
        { 0, 0, SEQ_ID_A6_BOSS | SEQ_FLAG, 0, 1, 1590 },
        { 1, 0, SEQ_ID_A6_BOSS | SEQ_FLAG, 1, 255, 50 },
        { 0, 0, SEQ_ID_GOOD_END, 0, 255, 1091 },
        { 1, 0, SEQ_ID_GOOD_END, 100, 255, 100 },
        { 0, 0, SEQ_ID_STAR_WOLF | SEQ_FLAG, 0, 255, 2120 },
        { 1, 0, SEQ_ID_STAR_WOLF | SEQ_FLAG, 30, 255, 150 },
        { 0, 0, SEQ_ID_TO_ANDROSS | SEQ_FLAG, 0, 0, 176 },
        { 0, 0, SEQ_ID_ANDROSS | SEQ_FLAG, 0, 255, 588 },
        { 0, 0, SEQ_ID_AND_BOSS | SEQ_FLAG, 0, 0, 2392 },
        { 1, 0, SEQ_ID_AND_BOSS | SEQ_FLAG, 10, 255, 50 },
        { 0, 0, SEQ_ID_AND_BRAIN | SEQ_FLAG, 0, 255, 1700 },
        { 1, 0, SEQ_ID_AND_BOSS | SEQ_FLAG, 10, 255, 250 },
        { 0, 0, SEQ_ID_A6_BOSS | SEQ_FLAG, 0, 255, 1600 },
        { 1, 0, SEQ_ID_A6_BOSS | SEQ_FLAG, 1, 255, 50 },
        { 0, 0, SEQ_ID_VE_CLEAR | SEQ_FLAG, 0, 255, 1091 },
        { 1, 0, SEQ_ID_VE_CLEAR | SEQ_FLAG, 80, 255, 160 },
        { 0, 0, SEQ_ID_ENDING, 0, 255, 9250 },
        { 255, 0, SEQ_ID_CORNERIA | SEQ_FLAG, 50, 255, 50 },
    },
    {
        { 0, 0, SEQ_ID_CO_INTRO, 0, 255, 1620 },
        { 0, 0, SEQ_ID_CORNERIA | SEQ_FLAG, 0, 255, 2490 },
        { 1, 0, SEQ_ID_CORNERIA | SEQ_FLAG, 50, 255, 50 },
        { 0, 0, SEQ_ID_CO_BOSS_1 | SEQ_FLAG, 0, 255, 1600 },
        { 1, 0, SEQ_ID_CO_BOSS_1 | SEQ_FLAG, 1, 255, 50 },
        { 0, 0, SEQ_ID_GOOD_END, 0, 255, 1091 },
        { 1, 0, SEQ_ID_GOOD_END, 100, 255, 100 },
        { 0, 0, SEQ_ID_ME_INTRO, 0, 255, 838 },
        { 0, 0, SEQ_ID_METEO | SEQ_FLAG, 0, 255, 1584 },
        { 1, 0, SEQ_ID_METEO | SEQ_FLAG, 150, 255, 150 },
        { 0, 0, SEQ_ID_WARP_ZONE | SEQ_FLAG, 0, 255, 1635 },
        { 1, 0, SEQ_ID_WARP_ZONE | SEQ_FLAG, 150, 255, 150 },
        { 0, 0, SEQ_ID_INTRO_51, 0, 255, 241 },
        { 0, 0, SEQ_ID_KATINA | SEQ_FLAG, 0, 255, 2184 },
        { 1, 0, SEQ_ID_KATINA | SEQ_FLAG, 1, 255, 100 },
        { 0, 0, SEQ_ID_KA_BOSS | SEQ_FLAG, 0, 1, 1115 },
        { 1, 0, SEQ_ID_KA_BOSS | SEQ_FLAG, 50, 255, 100 },
        { 0, 0, SEQ_ID_BAD_END, 0, 255, 1604 },
        { 1, 0, SEQ_ID_BAD_END, 100, 255, 100 },
        { 0, 0, SEQ_ID_INTRO_44, 0, 255, 242 },
        { 0, 0, SEQ_ID_SECTOR_X | SEQ_FLAG, 0, 255, 1291 },
        { 3, 0, SEQ_ID_BILL, 0, 255, 1000 },
        { 1, 0, SEQ_ID_SECTOR_X | SEQ_FLAG, 50, 255, 100 },
        { 0, 0, SEQ_ID_WARP_ZONE | SEQ_FLAG, 0, 255, 1635 },
        { 1, 0, SEQ_ID_WARP_ZONE | SEQ_FLAG, 150, 255, 150 },
        { 0, 0, SEQ_ID_INTRO_51, 0, 255, 241 },
        { 0, 0, SEQ_ID_SECTOR_Z | SEQ_FLAG, 0, 255, 1632 },
        { 1, 0, SEQ_ID_SECTOR_Z | SEQ_FLAG, 50, 255, 100 },
        { 0, 0, SEQ_ID_SZ_BOSS | SEQ_FLAG, 0, 1, 1115 },
        { 1, 0, SEQ_ID_SZ_BOSS | SEQ_FLAG, 1, 255, 50 },
        { 0, 0, SEQ_ID_GOOD_END, 0, 255, 1091 },
        { 1, 0, SEQ_ID_GOOD_END, 100, 255, 100 },
        { 0, 0, SEQ_ID_INTRO_51, 0, 255, 241 },
        { 0, 0, SEQ_ID_AREA_6 | SEQ_FLAG, 0, 255, 1906 },
        { 1, 0, SEQ_ID_AREA_6 | SEQ_FLAG, 50, 255, 100 },
        { 0, 0, SEQ_ID_A6_BOSS | SEQ_FLAG, 0, 1, 1590 },
        { 1, 0, SEQ_ID_A6_BOSS | SEQ_FLAG, 1, 255, 50 },
        { 0, 0, SEQ_ID_DEATH, 0, 255, 150 },
        { 0, 0, SEQ_ID_GAME_OVER, 0, 255, 1020 },
        { 1, 0, SEQ_ID_GAME_OVER, 100, 255, 100 },
        { 255, 0, SEQ_ID_CORNERIA | SEQ_FLAG, 50, 255, 50 },
    },
    {
        { 0, 0, SEQ_ID_OPENING, 0, 255, 2926 },
        { 0, 0, SEQ_ID_TITLE, 0, 255, 1251 },
        { 1, 0, SEQ_ID_TITLE, 200, 255, 200 },
        { 0, 0, SEQ_ID_MENU, 0, 255, 1636 },
        { 1, 0, SEQ_ID_MENU, 200, 255, 200 },
        { 0, 0, SEQ_ID_WORLD_MAP, 0, 255, 1560 },
        { 1, 0, SEQ_ID_WORLD_MAP, 200, 255, 200 },
        { 0, 0, SEQ_ID_CO_INTRO, 0, 255, 1618 },
        { 0, 0, SEQ_ID_INTRO_44, 0, 255, 242 },
        { 0, 0, SEQ_ID_INTRO_45, 0, 255, 582 },
        { 0, 0, SEQ_ID_ME_INTRO, 0, 255, 868 },
        { 0, 0, SEQ_ID_INTRO_51, 0, 255, 281 },
        { 0, 0, SEQ_ID_CORNERIA | SEQ_FLAG, 0, 255, 2490 },
        { 1, 0, SEQ_ID_CORNERIA | SEQ_FLAG, 200, 255, 200 },
        { 0, 0, SEQ_ID_METEO | SEQ_FLAG, 0, 255, 1584 },
        { 1, 0, SEQ_ID_METEO | SEQ_FLAG, 200, 255, 200 },
        { 0, 0, SEQ_ID_TITANIA | SEQ_FLAG, 0, 255, 1920 },
        { 1, 0, SEQ_ID_TITANIA | SEQ_FLAG, 200, 255, 200 },
        { 0, 0, SEQ_ID_SECTOR_X | SEQ_FLAG, 0, 255, 2290 },
        { 1, 0, SEQ_ID_SECTOR_X | SEQ_FLAG, 200, 255, 200 },
        { 0, 0, SEQ_ID_ZONESS | SEQ_FLAG, 0, 255, 2005 },
        { 1, 0, SEQ_ID_ZONESS | SEQ_FLAG, 200, 255, 200 },
        { 0, 0, SEQ_ID_AREA_6 | SEQ_FLAG, 0, 255, 1905 },
        { 1, 0, SEQ_ID_AREA_6 | SEQ_FLAG, 200, 255, 200 },
        { 0, 0, SEQ_ID_VENOM_1 | SEQ_FLAG, 0, 255, 1671 },
        { 1, 0, SEQ_ID_VENOM_1 | SEQ_FLAG, 200, 255, 200 },
        { 0, 0, SEQ_ID_SECTOR_Y | SEQ_FLAG, 0, 255, 2095 },
        { 1, 0, SEQ_ID_SECTOR_Y | SEQ_FLAG, 200, 255, 200 },
        { 0, 0, SEQ_ID_FORTUNA | SEQ_FLAG, 0, 255, 1632 },
        { 1, 0, SEQ_ID_FORTUNA | SEQ_FLAG, 200, 255, 200 },
        { 0, 0, SEQ_ID_KATINA | SEQ_FLAG, 0, 255, 2184 },
        { 1, 0, SEQ_ID_KATINA | SEQ_FLAG, 200, 255, 200 },
        { 0, 0, SEQ_ID_AQUAS, 0, 255, 2400 },
        { 1, 0, SEQ_ID_AQUAS, 200, 255, 200 },
        { 0, 0, SEQ_ID_WARP_ZONE | SEQ_FLAG, 0, 255, 1635 },
        { 1, 0, SEQ_ID_WARP_ZONE | SEQ_FLAG, 200, 255, 200 },
        { 0, 0, SEQ_ID_KATT, 0, 255, 389 },
        { 0, 0, SEQ_ID_BILL, 0, 255, 268 },
        { 0, 0, SEQ_ID_CO_BOSS_1 | SEQ_FLAG, 0, 255, 1598 },
        { 1, 0, SEQ_ID_CO_BOSS_1 | SEQ_FLAG, 200, 255, 200 },
        { 0, 0, SEQ_ID_ME_BOSS | SEQ_FLAG, 0, 0, 1470 },
        { 1, 0, SEQ_ID_ME_BOSS | SEQ_FLAG, 200, 255, 200 },
        { 0, 0, SEQ_ID_ME_BOSS | SEQ_FLAG, 0, 255, 1470 },
        { 1, 0, SEQ_ID_ME_BOSS | SEQ_FLAG, 200, 255, 200 },
        { 0, 0, SEQ_ID_BOSS_RESUME | SEQ_FLAG, 0, 255, 1311 },
        { 1, 0, SEQ_ID_BOSS_RESUME | SEQ_FLAG, 200, 255, 200 },
        { 0, 0, SEQ_ID_BO_BOSS | SEQ_FLAG, 0, 255, 1115 },
        { 1, 0, SEQ_ID_BO_BOSS | SEQ_FLAG, 200, 255, 200 },
        { 0, 0, SEQ_ID_STAR_WOLF | SEQ_FLAG, 0, 255, 2120 },
        { 1, 0, SEQ_ID_STAR_WOLF | SEQ_FLAG, 200, 255, 200 },
        { 0, 0, SEQ_ID_GOOD_END, 0, 255, 1091 },
        { 1, 0, SEQ_ID_GOOD_END, 200, 255, 200 },
        { 0, 0, SEQ_ID_BAD_END, 0, 255, 1604 },
        { 1, 0, SEQ_ID_BAD_END, 200, 255, 200 },
        { 0, 0, SEQ_ID_DEATH, 0, 255, 200 },
        { 0, 0, SEQ_ID_GAME_OVER, 0, 255, 1020 },
        { 1, 0, SEQ_ID_GAME_OVER, 200, 255, 200 },
        { 0, 0, SEQ_ID_TRAINING | SEQ_FLAG, 0, 255, 900 },
        { 1, 0, SEQ_ID_TRAINING | SEQ_FLAG, 200, 255, 200 },
        { 0, 0, SEQ_ID_VS_MENU, 0, 255, 665 },
        { 1, 0, SEQ_ID_VS_MENU, 200, 255, 200 },
        { 0, 0, SEQ_ID_VERSUS | SEQ_FLAG, 0, 255, 1647 },
        { 1, 0, SEQ_ID_VERSUS | SEQ_FLAG, 200, 255, 200 },
        { 0, 0, SEQ_ID_VS_HURRY | SEQ_FLAG, 0, 255, 1667 },
        { 1, 0, SEQ_ID_VS_HURRY | SEQ_FLAG, 200, 255, 200 },
        { 0, 0, SEQ_ID_TO_ANDROSS | SEQ_FLAG, 0, 0, 176 },
        { 0, 0, SEQ_ID_ANDROSS | SEQ_FLAG, 0, 255, 588 },
        { 1, 0, SEQ_ID_ANDROSS | SEQ_FLAG, 200, 255, 200 },
        { 0, 0, SEQ_ID_AND_BOSS | SEQ_FLAG, 0, 0, 2391 },
        { 1, 0, SEQ_ID_AND_BOSS | SEQ_FLAG, 200, 255, 200 },
        { 0, 0, SEQ_ID_AND_BOSS | SEQ_FLAG, 0, 255, 2391 },
        { 1, 0, SEQ_ID_AND_BOSS | SEQ_FLAG, 200, 255, 200 },
        { 0, 0, SEQ_ID_AND_BRAIN | SEQ_FLAG, 0, 255, 1700 },
        { 1, 0, SEQ_ID_AND_BRAIN | SEQ_FLAG, 200, 255, 200 },
        { 0, 0, SEQ_ID_VE_CLEAR | SEQ_FLAG, 0, 255, 1459 },
        { 1, 0, SEQ_ID_VE_CLEAR | SEQ_FLAG, 200, 255, 200 },
        { 0, 0, SEQ_ID_ENDING, 0, 255, 9250 },
        { 1, 0, SEQ_ID_ENDING, 200, 255, 200 },
        { 255, 0, SEQ_ID_CORNERIA | SEQ_FLAG, 50, 255, 50 },
    },
};

s32 D_800C737C = 0; // unused. file split?
f32 D_800C7380 = 1.0f;
u32 sNextVoiceId = 0;
u32 sCurrentVoiceId = 0;
u8 sSetNextVoiceId = 0;
u8 D_800C7390 = 0;
u8 sMuteBgmForVoice = 0;

void func_80016A50(void) {
}

f32 Audio_GetSfxFalloff(u8 bankId, u8 entryIndex) {
    f32 cutoff;
    f32 midDist;
    f32 distance;
    f32 falloff;
    f32 midrange;
    f32 range;

    if (SFX_BIT09(sSfxBanks[bankId][entryIndex].sfxId)) {
        return 1.0f;
    }
    distance = sSfxBanks[bankId][entryIndex].distance;
    if (distance > 33000.0f) {
        falloff = 0.0f;
    } else {
        switch (SFX_RANGE_MASK(sSfxBanks[bankId][entryIndex].sfxId)) {
            default:
                range = 1650.0f;
                break;
            case 1 << 16:
                range = 2200.0f;
                break;
            case 2 << 16:
                range = 3142.8572f;
                break;
            case 3 << 16:
                range = 6346.1543f;
                break;
        }
        cutoff = range / 5.0f;
        if (distance < range / 5.0f) {
            falloff = 1.0f;
        } else if (distance < range) {
            midDist = range - cutoff;
            midrange = distance - cutoff;
            falloff = (((midDist - midrange) / midDist) * 0.19f) + 0.81f;
        } else {
            falloff = (1.0f - ((distance - range) / (33000.0f - range))) * 0.81f;
        }
        falloff = SQ(falloff);
    }
    return falloff;
}

s8 Audio_GetSfxReverb(u8 bankId, u8 entryIndex, u8 channelId) {
    s32 totalReverb;
    s8 distReverb = 0;
    s8 scriptReverb = 0;

    if (!SFX_BIT10(sSfxBanks[bankId][entryIndex].sfxId)) {
        if (sSfxBanks[bankId][entryIndex].distance < 8250.0f) {
            distReverb = (sSfxBanks[bankId][entryIndex].distance / 8250.0f) * 40.0f;
        } else {
            distReverb = 40;
        }
    }
    if (IS_SEQUENCE_CHANNEL_VALID(gSeqPlayers[SEQ_PLAYER_SFX].channels[channelId])) {
        scriptReverb = gSeqPlayers[SEQ_PLAYER_SFX].channels[channelId]->seqScriptIO[6];
    }
    if (scriptReverb == -1) {
        scriptReverb = 0;
    }
    totalReverb = *sSfxBanks[bankId][entryIndex].reverbAdd + distReverb + scriptReverb + sBaseReverb + sAudioSpecReverb;
    totalReverb = MIN(127, totalReverb);
    return totalReverb;
}

s8 Audio_GetSfxPan(f32 xPos, f32 zPos, u8 mode) {
    if (sSfxChannelLayout != 3) {
        f32 absx = ABSF(xPos);
        f32 absz = ABSF(zPos);
        f32 pan;

        if ((absx < 1.0f) && (absz < 1.0f)) {
            return 64;
        }
        absx = MIN(1200.0f, absx);
        absz = MIN(1200.0f, absz);

        if ((xPos == 0) && (zPos == 0)) {
            pan = 0.5f;
        } else if ((xPos >= 0.f) && (absz <= absx)) {
            pan = 1.0f - ((2400.0f - absx) / (10.0f * (2400.0f - absz)));
        } else if ((xPos < 0.0f) && (absz <= absx)) {
            pan = (2400.0f - absx) / (10.0f * (2400.0f - absz));
        } else {
            pan = (xPos / (2.5f * absz)) + 0.5f;
        }
        return ROUND(pan * 127.0f);
    } else if (mode != 4) {
        return ((mode & 1) * 127);
    }
    return 64;
}

f32 Audio_GetSfxFreqMod(u8 bankId, u8 entryIndex) {
    f32 distance;
    f32 freqMod = 1.0f;

    if (SFX_BIT08(sSfxBanks[bankId][entryIndex].sfxId)) {
        freqMod -= ((gAudioRandom % 16) / 192.0f);
    }
    distance = sSfxBanks[bankId][entryIndex].distance;
    if (!SFX_BIT09(sSfxBanks[bankId][entryIndex].sfxId)) {
        if (distance >= 33000.0f) {
            freqMod += 0.2f;
        } else {
            freqMod += 0.2f * (distance / 33000.0f);
        }
    }
    if ((sSfxChannelLayout != 0) && (sSfxBanks[bankId][entryIndex].token & 2)) {
        freqMod *= 1.1f;
    }
    return freqMod;
}

void Audio_SetSfxProperties(u8 bankId, u8 entryIndex, u8 channelId) {
    f32 volumeMod = 1.0f;
    s8 reverb = 0;
    f32 freqMod = 1.0f;
    s8 pan = 64;
    SfxBankEntry* entry = &sSfxBanks[bankId][entryIndex];

    switch (bankId) {
        case 0:
        case 1:
        case 2:
        case 3:
            if (entry->state == 2) {
                AUDIOCMD_CHANNEL_SET_IO(SEQ_PLAYER_SFX, channelId, 1, gLevelType);
            }
            if (SFX_BIT13(entry->sfxId) && (*entry->zPos > 0.0f)) {
                f32 yScaled = *entry->yPos / 2.5f;

                entry->distance = SQ(*entry->xPos) + SQ(yScaled);
            }
            entry->distance = sqrtf(entry->distance);
            volumeMod = (Audio_GetSfxFalloff(bankId, entryIndex) * *entry->volMod) * sSfxVolumeMods[bankId].value;
            reverb = Audio_GetSfxReverb(bankId, entryIndex, channelId);
            freqMod = Audio_GetSfxFreqMod(bankId, entryIndex) * *entry->freqMod;
            if ((bankId != 0) || !(*entry->zPos > -200.0f) || !(*entry->zPos < 200.0f) || (sSfxChannelLayout == 3)) {
                pan = Audio_GetSfxPan(*entry->xPos, *entry->zPos, entry->token);
            }
            break;
        case 4:
            if (sSfxChannelLayout == 3) {
                if (entry->token != 4) {
                    pan = (entry->token & 1) * 127;
                }
            }
            break;
    }
    if (volumeMod != sSfxChannelState[channelId].volMod) {
        AUDIOCMD_CHANNEL_SET_VOL_SCALE(SEQ_PLAYER_SFX, channelId, volumeMod);
        sSfxChannelState[channelId].volMod = volumeMod;
    }
    if (reverb != sSfxChannelState[channelId].reverb) {
        AUDIOCMD_CHANNEL_SET_REVERB_VOLUME(SEQ_PLAYER_SFX, channelId, reverb);
        sSfxChannelState[channelId].reverb = reverb;
    }
    if (freqMod != sSfxChannelState[channelId].freqMod) {
        AUDIOCMD_CHANNEL_SET_FREQ_SCALE(SEQ_PLAYER_SFX, channelId, freqMod);
        sSfxChannelState[channelId].freqMod = freqMod;
    }
    if (pan != sSfxChannelState[channelId].pan) {
        AUDIOCMD_CHANNEL_SET_PAN(SEQ_PLAYER_SFX, channelId, pan);
        sSfxChannelState[channelId].pan = pan;
    }
}

f32 Audio_UpdateDopplerShift(f32* srcPos, f32* srcVel, f32 soundSpeed, f32* curDopplerShift) {
    f32 xVel;
    f32 zVel;
    f32 xPos;
    f32 zPos;
    f32 xzDist;
    f32 xPosNext;
    f32 zPosNext;
    f32 xzDistNext;
    f32 step;
    f32 newShift;
    f32 relativeSpeed;
    f32 targetDopplerShift;
    s32 pad;

    xPos = srcPos[0];
    zPos = srcPos[2];
    xVel = srcVel[0];
    zVel = srcVel[2];
    xzDist = sqrtf(SQ(xPos) + SQ(zPos));
    xPosNext = xPos + xVel;
    zPosNext = zPos + zVel;
    xzDistNext = sqrtf(SQ(xPosNext) + SQ(zPosNext));
    relativeSpeed = (xzDist - xzDistNext) / soundSpeed;
    targetDopplerShift = 1.0f / (1.0f - relativeSpeed);

    step = targetDopplerShift - *curDopplerShift;
    newShift = *curDopplerShift;
    if (step != 0.0f) {
        if (step > 0.2f) {
            newShift += 0.2f;
        } else if (step < -0.2f) {
            newShift -= 0.2f;
        } else {
            newShift += step;
        }
    }
    *curDopplerShift = newShift;

    if (newShift > 4.0f) {
        newShift = 4.0f;
    } else if (newShift < 0.1f) {
        newShift = 0.1f;
    }

    return newShift;
}

void func_80017494(void) {
    u8 i;

    for (i = 0; D_800C5D6C[sNewAudioSpecId][i] != 0xFF; i++) {
        AUDIOCMD_GLOBAL_SYNC_LOAD_INSTRUMENT(0, D_800C5D6C[sNewAudioSpecId][i], 0);
    }
}

void func_80017550(void) {
    if (sNewAudioSpecId == 12) {
        AUDIOCMD_GLOBAL_SYNC_LOAD_SEQ_PARTS(14, 0);
    }
}

void Audio_ResetSfxChannelState(void) {
    u8 i;

    sBaseReverb = 0;
    sAudioSpecReverb = D_800C5E38[sNewAudioSpecId];
    for (i = 0; i < 16; i++) {
        sSfxChannelState[i].volMod = 1.0f;
        sSfxChannelState[i].freqMod = 1.0f;
        sSfxChannelState[i].reverb = 0;
        sSfxChannelState[i].pan = 64;
    }
}

void Audio_StartSequence(u8 seqPlayId, u8 seqId, u8 seqArgs, u16 fadeInTime) {
    u8 i;
    s32 pad;

    if (!sStartSeqDisabled || (seqPlayId == SEQ_PLAYER_SFX)) {
        AUDIOCMD_GLOBAL_INIT_SEQPLAYER((u32) seqPlayId, (u32) seqId, 0, fadeInTime);
        sActiveSequences[seqPlayId].prevSeqId = sActiveSequences[seqPlayId].seqId = seqId | ((seqArgs) << 8);
        if (sActiveSequences[seqPlayId].mainVolume.mod != 1.0f) {
            AUDIOCMD_SEQPLAYER_FADE_VOLUME_SCALE((u32) seqPlayId, sActiveSequences[seqPlayId].mainVolume.mod);
        }
        sActiveSequences[seqPlayId].tempo.timer = 0;
        sActiveSequences[seqPlayId].tempoOriginal = 0;
        sActiveSequences[seqPlayId].tempoCmd = 0;
        for (i = 0; i < 16; i++) {
            sActiveSequences[seqPlayId].channelMod[i].volume.value = 1.0f;
            sActiveSequences[seqPlayId].channelMod[i].volume.timer = 0;
            sActiveSequences[seqPlayId].channelMod[i].freq.value = 1.0f;
            sActiveSequences[seqPlayId].channelMod[i].freq.timer = 0;
        }
        sActiveSequences[seqPlayId].volChannelFlags = sActiveSequences[seqPlayId].freqModChannelFlags = 0;
    }
}

void Audio_StopSequence(u8 seqPlayId, u16 fadeOutTime) {
    AUDIOCMD_GLOBAL_DISABLE_SEQPLAYER(seqPlayId, fadeOutTime);
    sActiveSequences[seqPlayId].seqId = SEQ_ID_NONE;
}

void Audio_ProcessSeqCmd(u32 seqCmd) {
    u16 flag;
    u16 channelDisableMask;
    u16 fadeTimer;
    u16 val;
    s32 priority;
    u8 i; // sp63
    u8 specId;
    u8 sp61;
    u8 ioPort;
    u8 channel;
    u8 found;
    u8 muteFlag;
    u8 duration;
    u8 seqNumber;
    u8 subOp;
    u8 seqPlayId;
    u8 seqArgs;
    u8* tempptr; // sp54
    u8* tempPtr2;
    u32 sp4C;

    seqPlayId = (seqCmd & 0x0F000000) >> 0x18;
    switch ((seqCmd >> 0x1C) & 0xFF) {
        case SEQCMD_OP_PLAY_SEQUENCE:
            seqNumber = seqCmd & 0xFF;
            seqArgs = (seqCmd & 0xFF00) >> 8;
            fadeTimer = (seqCmd & 0xFF0000) >> 13;
            if (sActiveSequences[seqPlayId].isWaitingForFonts == 0) {
                if (seqArgs < 0x80) {
                    Audio_StartSequence(seqPlayId, seqNumber, seqArgs, fadeTimer);
                } else {
                    sActiveSequences[seqPlayId].startSeqCmd = seqCmd & ~0x8000;
                    sActiveSequences[seqPlayId].isWaitingForFonts = 1;
                    Audio_StopSequence(seqPlayId, 1);
                    if (sActiveSequences[seqPlayId].prevSeqId != SEQ_ID_NONE) {
                        tempptr = AudioThread_GetFontsForSequence(seqNumber, &sp4C);
                        tempPtr2 = AudioThread_GetFontsForSequence(sActiveSequences[seqPlayId].prevSeqId & 0xFF, &sp4C);
                        if (tempptr[0] != tempPtr2[0]) {
                            AUDIOCMD_GLOBAL_DISCARD_SEQ_FONTS(seqNumber);
                        }
                    }
                    AUDIOCMD_GLOBAL_ASYNC_LOAD_FONT(seqNumber, 20, (s8) (seqPlayId + 1));
                }
            }
            break;
        case SEQCMD_OP_STOP_SEQUENCE:
            fadeTimer = (seqCmd & 0xFF0000) >> 13;
            Audio_StopSequence(seqPlayId, fadeTimer);
            return;
        case SEQCMD_OP_QUEUE_SEQUENCE:
            seqNumber = seqCmd & 0xFF;
            seqArgs = (seqCmd & 0xFF00) >> 8;
            fadeTimer = (seqCmd & 0xFF0000) >> 13;
            priority = seqArgs;
            for (i = 0; i < sNumSeqRequests[seqPlayId]; i++) {
                if (seqNumber == sSeqRequests[seqPlayId][i].seqId) {
                    if (i == 0) {
                        Audio_StartSequence(seqPlayId, seqNumber, seqArgs, fadeTimer);
                    }
                    return;
                }
            }
            found = sNumSeqRequests[seqPlayId];
            for (i = 0; i < sNumSeqRequests[seqPlayId]; i++) {
                if (seqArgs >= sSeqRequests[seqPlayId][i].priority) {
                    found = i;
                    i = sNumSeqRequests[seqPlayId];
                }
            }
            if ((found != sNumSeqRequests[seqPlayId]) || (found == 0)) {
                if (sNumSeqRequests[seqPlayId] < 5) {
                    sNumSeqRequests[seqPlayId]++;
                }
                for (i = sNumSeqRequests[seqPlayId] - 1; i != found; i--) {
                    sSeqRequests[seqPlayId][i].priority = sSeqRequests[seqPlayId][i - 1].priority;
                    sSeqRequests[seqPlayId][i].seqId = sSeqRequests[seqPlayId][i - 1].seqId;
                }
                sSeqRequests[seqPlayId][found].priority = seqArgs;
                sSeqRequests[seqPlayId][found].seqId = seqNumber;
            }
            if (found == 0) {
                Audio_StartSequence(seqPlayId, seqNumber, seqArgs, fadeTimer);
            }
            break;
        case SEQCMD_OP_UNQUEUE_SEQUENCE:
            fadeTimer = (seqCmd & 0xFF0000) >> 0xD;
            found = sNumSeqRequests[seqPlayId];
            for (i = 0; i < sNumSeqRequests[seqPlayId]; i++) {
                seqNumber = seqCmd & 0xFF;
                if (sSeqRequests[seqPlayId][i].seqId == seqNumber) {
                    found = i;
                    i = sNumSeqRequests[seqPlayId];
                }
            }
            if (found != sNumSeqRequests[seqPlayId]) {
                for (i = found; i < sNumSeqRequests[seqPlayId] - 1; i++) {
                    sSeqRequests[seqPlayId][i].priority = sSeqRequests[seqPlayId][i + 1].priority;
                    sSeqRequests[seqPlayId][i].seqId = sSeqRequests[seqPlayId][i + 1].seqId;
                }
                sNumSeqRequests[seqPlayId]--;
            }
            if (found == 0) {
                Audio_StopSequence(seqPlayId, fadeTimer);
                if (sNumSeqRequests[seqPlayId] != 0) {

                    Audio_StartSequence(seqPlayId, sSeqRequests[seqPlayId][0].seqId,
                                        sSeqRequests[seqPlayId][0].priority, fadeTimer);
                }
            }
            break;
        case SEQCMD_OP_SET_SEQPLAYER_VOLUME:
            val = seqCmd & 0xFF;
            duration = (seqCmd & 0xFF0000) >> 0xF;

            if (duration == 0) {
                duration++;
            }
            sActiveSequences[seqPlayId].mainVolume.target = val / 127.0f;
            if (sActiveSequences[seqPlayId].mainVolume.mod != sActiveSequences[seqPlayId].mainVolume.target) {
                sActiveSequences[seqPlayId].mainVolume.step =
                    (sActiveSequences[seqPlayId].mainVolume.mod - sActiveSequences[seqPlayId].mainVolume.target) /
                    duration;
                sActiveSequences[seqPlayId].mainVolume.timer = duration;
            }
            break;
        case SEQCMD_OP_SET_SEQPLAYER_FREQ:
            val = (seqCmd & 0xFFFF);
            duration = (seqCmd & 0xFF0000) >> 0xF;

            if (duration == 0) {
                duration++;
            }
            for (i = 0; i < 16; i++) {
                sActiveSequences[seqPlayId].channelMod[i].freq.target = val / 1000.0f;
                sActiveSequences[seqPlayId].channelMod[i].freq.step =
                    (sActiveSequences[seqPlayId].channelMod[i].freq.value -
                     sActiveSequences[seqPlayId].channelMod[i].freq.target) /
                    duration;
                sActiveSequences[seqPlayId].channelMod[i].freq.timer = duration;
            }
            sActiveSequences[seqPlayId].freqModChannelFlags = 0xFFFF;
            break;
        case SEQCMD_OP_SET_CHANNEL_VOLUME:
            val = (seqCmd & 0xFF);
            channel = (seqCmd & 0xF00) >> 8;
            duration = (seqCmd & 0xFF0000) >> 0xF;

            if (duration == 0) {
                duration++;
            }

            sActiveSequences[seqPlayId].channelMod[channel].volume.target = val / 127.0f;
            if (sActiveSequences[seqPlayId].channelMod[channel].volume.value !=
                sActiveSequences[seqPlayId].channelMod[channel].volume.target) {
                sActiveSequences[seqPlayId].channelMod[channel].volume.step =
                    (sActiveSequences[seqPlayId].channelMod[channel].volume.value -
                     sActiveSequences[seqPlayId].channelMod[channel].volume.target) /
                    duration;
                sActiveSequences[seqPlayId].channelMod[channel].volume.timer = duration;
                sActiveSequences[seqPlayId].freqModChannelFlags |= 1 << channel;
            }
            break;
        case SEQCMD_OP_SET_SEQPLAYER_IO:
            val = seqCmd & 0xFF;
            ioPort = ((seqCmd & 0xFF0000) >> 0x10); // may be misnamed
            AUDIOCMD_SEQPLAYER_SET_IO(seqPlayId, ioPort, val);
            // AudioThread_QueueCmdS8(((seqPlayId & 0xFF) << 0x10) | 0x46000000 | (temp3 << 8), temp4);
            break;
        case SEQCMD_OP_SET_CHANNEL_IO:
            val = seqCmd & 0xFF;
            channel = (seqCmd & 0xF00) >> 8;

            ioPort = (seqCmd & 0xFF0000) >> 0x10;
            if (!(sActiveSequences[seqPlayId].channelPortMask & (1 << channel))) {
                AUDIOCMD_CHANNEL_SET_IO(seqPlayId, (u32) channel, ioPort, val);
                // AudioThread_QueueCmdS8(((seqPlayId & 0xFF) << 0x10) | 0x06000000 | ((temp_a2_5 & 0xFF) << 8) | temp3,
                // temp4);
            }
            break;
        case SEQCMD_OP_SET_CHANNEL_IO_DISABLE_MASK:
            channelDisableMask = seqCmd & 0xFFFF;
            sActiveSequences[seqPlayId].channelPortMask = channelDisableMask;
            break;
        case SEQCMD_OP_SET_CHANNEL_DISABLE_MASK:
            channelDisableMask = seqCmd & 0xFFFF;

            flag = 1;
            for (i = 0; i < 16; i++) {
                AUDIOCMD_CHANNEL_SET_MUTE(seqPlayId, (u32) i, (channelDisableMask & flag) ? 1 : 0);
                flag <<= 1;
            }
            break;
        case SEQCMD_OP_TEMPO_CMD:
            sActiveSequences[seqPlayId].tempoCmd = seqCmd;
            break;
        case SEQCMD_OP_SETUP_CMD:
            subOp = (seqCmd & 0xF00000) >> 20;
            if (subOp != SEQCMD_SUB_OP_SETUP_RESET_SETUP_CMDS) {
                found = sActiveSequences[seqPlayId].setupCmdNum++;
                if (found < 5) {
                    sActiveSequences[seqPlayId].setupCmd[found] = seqCmd;
                    sActiveSequences[seqPlayId].setupCmdTimer = 2;
                }
            } else {
                sActiveSequences[seqPlayId].setupCmdNum = 0;
            }
            break;
        case SEQCMD_OP_GLOBAL_CMD:
            val = seqCmd & 0xFF;
            subOp = (seqCmd & 0xF00) >> 8;

            switch (subOp) {
                case SEQCMD_SUB_OP_GLOBAL_SET_SOUND_MODE:
                    AUDIOCMD_GLOBAL_SET_SOUND_MODE(sSoundModeList[val]);
                    // AudioThread_QueueCmdS32(0xF0000000, sSoundModeList[temp11]);
                    break;
                case SEQCMD_SUB_OP_GLOBAL_DISABLE_NEW_SEQUENCES:
                    sStartSeqDisabled = val & 1;
                    break;
            }
            break;
        case SEQCMD_OP_RESET_AUDIO_HEAP:
            specId = seqCmd & 0xFF;
            sSfxChannelLayout = (seqCmd & 0xFF00) >> 8;
            sp61 = sNewAudioSpecId;
            sNewAudioSpecId = specId;

            if (sp61 != specId) {
                AudioThread_ResetAudioHeap(specId);
                func_8001DE1C(sp61);
                AUDIOCMD_GLOBAL_STOP_AUDIOCMDS();

            } else {
                Audio_StopSequence(SEQ_PLAYER_BGM, 1);
                Audio_StopSequence(SEQ_PLAYER_FANFARE, 1);
            }
            break;
    }
}

void Audio_QueueSeqCmd(s32 seqCmd) {
    sAudioSeqCmds[sSeqCmdWritePos] = seqCmd;
    sSeqCmdWritePos++;
}

void Audio_ProcessSeqCmds(void) {
    while (sSeqCmdWritePos != sSeqCmdReadPos) {
        Audio_ProcessSeqCmd(sAudioSeqCmds[sSeqCmdReadPos++]);
    }
}

u16 Audio_GetActiveSeqId(u8 seqPlayId) {
    if (!gSeqPlayers[seqPlayId].enabled) {
        return 0xFFFF;
    }
    return sActiveSequences[seqPlayId].seqId;
}

s32 Audio_SeqCmdNotQueued(s32 seqCmd) {
    s32 notFound = true;
    u8 i;

    for (i = sSeqCmdReadPos; i < sSeqCmdWritePos; i++) {
        if (seqCmd == sAudioSeqCmds[i]) {
            notFound = false;
            i = sSeqCmdWritePos;
        }
    }
    return notFound;
}

s32 Audio_SeqCmdValueNotQueued(s32 cmdVal, s32 cmdMask) {
    s32 notFound = true;
    u8 i;

    for (i = sSeqCmdReadPos; i < sSeqCmdWritePos; i++) {
        if (cmdVal == (sAudioSeqCmds[i] & cmdMask)) {
            notFound = false;
            i = sSeqCmdWritePos;
        }
    }
    return notFound;
}

void Audio_ResetSequenceRequests(u8 seqPlayId) {
    sNumSeqRequests[seqPlayId] = 0;
}

void func_800184EC(u8 seqPlayId, u8 setupOpDisable) {
    u8 i;

    for (i = 0; i < sActiveSequences[seqPlayId].setupCmdNum; i++) {
        u8 setupOp = ((sActiveSequences[seqPlayId].setupCmd[i] & 0xF00000) >> 20);

        if (setupOp == setupOpDisable) {
            sActiveSequences[seqPlayId].setupCmd[i] = 0xFF000000;
        }
    }
}

void Audio_SetSequenceFade(u8 seqPlayId, u8 fadeModId, u8 fadeMod, u8 fadeTime) {
    sActiveSequences[seqPlayId].mainVolume.fadeMod[fadeModId] = fadeMod;
    sActiveSequences[seqPlayId].mainVolume.fadeTimer = fadeTime;
    sActiveSequences[seqPlayId].mainVolume.fadeActive = true;
}

void Audio_UpdateActiveSequences(void) {
    u8 seqPlayId;
    u8 i;
    u8 tempoTimer;
    u8 channelId;
    u16 tempoTarget;
    u16 prevTempo;
    u16 seqId;
    u8 tempoOp;
    u8 setupSeqPlayId;
    u8 val1;
    u8 setupOp;
    u8 val2;
    u8 temp2;
    s32 temp;
    u32 cmd;
    f32 fadeMod;
    u32 sp70;
    s32 pad1;
    s32 pad2;

    for (seqPlayId = 0; seqPlayId < 4; seqPlayId++) {
        if ((sActiveSequences[seqPlayId].isWaitingForFonts != 0)) {
            switch ((s32) AudioThread_GetAsyncLoadStatus(&sp70)) {
                case SEQ_PLAYER_BGM + 1:
                case SEQ_PLAYER_FANFARE + 1:
                case SEQ_PLAYER_SFX + 1:
                case SEQ_PLAYER_VOICE + 1:
                    sActiveSequences[seqPlayId].isWaitingForFonts = 0;
                    Audio_ProcessSeqCmd(sActiveSequences[seqPlayId].startSeqCmd);
                    break;
            }
        }
        if (sActiveSequences[seqPlayId].mainVolume.fadeActive != 0) {
            fadeMod = 1.0f;
            for (i = 0; i < 3; i++) {
                fadeMod *= sActiveSequences[seqPlayId].mainVolume.fadeMod[i] / 127.0f;
            }
            SEQCMD_SET_SEQPLAYER_VOLUME(seqPlayId, sActiveSequences[seqPlayId].mainVolume.fadeTimer,
                                        (u8) (fadeMod * 127.0f));
            sActiveSequences[seqPlayId].mainVolume.fadeActive = false;
        }
        if (sActiveSequences[seqPlayId].mainVolume.timer != 0) {
            sActiveSequences[seqPlayId].mainVolume.timer--;
            if (sActiveSequences[seqPlayId].mainVolume.timer != 0) {
                sActiveSequences[seqPlayId].mainVolume.mod -= sActiveSequences[seqPlayId].mainVolume.step;
            } else {
                sActiveSequences[seqPlayId].mainVolume.mod = sActiveSequences[seqPlayId].mainVolume.target;
            }
            AUDIOCMD_SEQPLAYER_FADE_VOLUME_SCALE((u32) seqPlayId, sActiveSequences[seqPlayId].mainVolume.mod);
        }
        if (sActiveSequences[seqPlayId].tempoCmd != 0) {
            cmd = sActiveSequences[seqPlayId].tempoCmd;
            temp = cmd & 0xFFF;
            temp2 = (cmd & 0xFF0000) >> 0xF;
            tempoTimer = temp2;
            tempoTarget = temp;

            if (temp2 == 0) {
                tempoTimer = temp2 + 1;
            }
            if (gSeqPlayers[seqPlayId].enabled) {
                prevTempo = gSeqPlayers[seqPlayId].tempo / 48;
                tempoOp = ((cmd & 0xF000) >> 0xC);

                switch (tempoOp) {
                    case SEQCMD_SUB_OP_TEMPO_SPEED_UP:
                        tempoTarget = tempoTarget + prevTempo;
                        break;
                    case SEQCMD_SUB_OP_TEMPO_SLOW_DOWN:
                        if (tempoTarget < prevTempo) {
                            tempoTarget = prevTempo - tempoTarget;
                        }
                        break;
                    case SEQCMD_SUB_OP_TEMPO_SCALE:
                        tempoTarget = prevTempo * (tempoTarget / 100.0f);
                        break;
                    case SEQCMD_SUB_OP_TEMPO_RESET:
                        if (sActiveSequences[seqPlayId].tempoOriginal != 0) {
                            tempoTarget = sActiveSequences[seqPlayId].tempoOriginal;
                        } else {
                            tempoTarget = prevTempo;
                        }
                        break;
                }
                if (tempoTarget > 300) {
                    tempoTarget = 300;
                }
                if (!sActiveSequences[seqPlayId].tempoOriginal) {
                    sActiveSequences[seqPlayId].tempoOriginal = prevTempo;
                }
                sActiveSequences[seqPlayId].tempo.target = tempoTarget;
                sActiveSequences[seqPlayId].tempo.value = (s32) gSeqPlayers[seqPlayId].tempo / 48;

                sActiveSequences[seqPlayId].tempo.step =
                    (sActiveSequences[seqPlayId].tempo.value - sActiveSequences[seqPlayId].tempo.target) / tempoTimer;
                sActiveSequences[seqPlayId].tempo.timer = tempoTimer;
                sActiveSequences[seqPlayId].tempoCmd = 0;
            }
        }
        if (sActiveSequences[seqPlayId].tempo.timer != 0) {
            sActiveSequences[seqPlayId].tempo.timer--;
            if (sActiveSequences[seqPlayId].tempo.timer != 0) {
                sActiveSequences[seqPlayId].tempo.value -= sActiveSequences[seqPlayId].tempo.step;
            } else {
                sActiveSequences[seqPlayId].tempo.value = sActiveSequences[seqPlayId].tempo.target;
            }
            AUDIOCMD_SEQPLAYER_SET_TEMPO((u32) seqPlayId, (s32) sActiveSequences[seqPlayId].tempo.value);
        }
        if (sActiveSequences[seqPlayId].volChannelFlags != 0) {
            for (channelId = 0; channelId < 16; channelId++) {
                if (sActiveSequences[seqPlayId].channelMod[channelId].volume.timer != 0) {
                    sActiveSequences[seqPlayId].channelMod[channelId].volume.timer--;
                    if (sActiveSequences[seqPlayId].channelMod[channelId].volume.timer) {
                        sActiveSequences[seqPlayId].channelMod[channelId].volume.value -=
                            sActiveSequences[seqPlayId].channelMod[channelId].volume.step;
                    } else {
                        sActiveSequences[seqPlayId].channelMod[channelId].volume.value =
                            sActiveSequences[seqPlayId].channelMod[channelId].volume.target;
                        sActiveSequences[seqPlayId].volChannelFlags ^= 1 << channelId;
                    }
                    AUDIOCMD_CHANNEL_SET_VOL_SCALE((u32) seqPlayId, (u32) channelId,
                                                   sActiveSequences[seqPlayId].channelMod[channelId].volume.value);
                }
            }
        }
        if (sActiveSequences[seqPlayId].freqModChannelFlags != 0) {
            for (channelId = 0; channelId < 16; channelId++) {
                if (sActiveSequences[seqPlayId].channelMod[channelId].freq.timer != 0) {
                    sActiveSequences[seqPlayId].channelMod[channelId].freq.timer--;
                    if (sActiveSequences[seqPlayId].channelMod[channelId].freq.timer != 0) {
                        sActiveSequences[seqPlayId].channelMod[channelId].freq.value -=
                            sActiveSequences[seqPlayId].channelMod[channelId].freq.step;
                    } else {
                        sActiveSequences[seqPlayId].channelMod[channelId].freq.value =
                            sActiveSequences[seqPlayId].channelMod[channelId].freq.target;
                        sActiveSequences[seqPlayId].freqModChannelFlags ^= 1 << channelId;
                    }
                    AUDIOCMD_CHANNEL_SET_FREQ_SCALE((u32) seqPlayId, (u32) channelId,
                                                    sActiveSequences[seqPlayId].channelMod[channelId].freq.value);
                }
            }
        }
        if (sActiveSequences[seqPlayId].setupCmdNum == 0) {
            continue;
        }
        if (!Audio_SeqCmdValueNotQueued(SEQCMD_OP_MASK, SEQCMD_OP_RESET_AUDIO_HEAP << 28)) {
            sActiveSequences[seqPlayId].setupCmdNum = 0;
            break;
        }
        if (sActiveSequences[seqPlayId].setupCmdTimer != 0) {
            sActiveSequences[seqPlayId].setupCmdTimer--;
        } else if (!gSeqPlayers[seqPlayId].enabled) {
            for (i = 0; i < sActiveSequences[seqPlayId].setupCmdNum; i++) {
                setupOp = (sActiveSequences[seqPlayId].setupCmd[i] & 0xF00000) >> 0x14;

                setupSeqPlayId = (sActiveSequences[seqPlayId].setupCmd[i] & 0xF0000) >> 0x10;
                val2 = (sActiveSequences[seqPlayId].setupCmd[i] & 0xFF00) >> 8;
                val1 = sActiveSequences[seqPlayId].setupCmd[i] & 0xFF;
                switch (setupOp) {
                    case SEQCMD_SUB_OP_SETUP_RESTORE_SEQPLAYER_VOLUME:
                        Audio_SetSequenceFade(setupSeqPlayId, 1, 127, val2);
                        break;
                    case SEQCMD_SUB_OP_SETUP_SEQ_UNQUEUE:
                        SEQCMD_UNQUEUE_SEQUENCE(seqPlayId, 0, sActiveSequences[seqPlayId].seqId);
                        break;
                    case SEQCMD_SUB_OP_SETUP_RESTART_SEQ:
                        SEQCMD_PLAY_SEQUENCE(setupSeqPlayId, 1, 0, sActiveSequences[setupSeqPlayId].seqId);
                        sActiveSequences[setupSeqPlayId].mainVolume.fadeActive = true;
                        sActiveSequences[setupSeqPlayId].mainVolume.fadeMod[1] = 127;
                        break;
                    case SEQCMD_SUB_OP_SETUP_TEMPO_SCALE:
                        SEQCMD_SCALE_TEMPO(setupSeqPlayId, val2, val1);
                        break;
                    case SEQCMD_SUB_OP_SETUP_TEMPO_RESET:
                        SEQCMD_RESET_TEMPO(setupSeqPlayId, val1);
                        break;
                    case SEQCMD_SUB_OP_SETUP_PLAY_SEQ:
                        seqId = sActiveSequences[seqPlayId].setupCmd[i] & 0xFFFF;
                        SEQCMD_PLAY_SEQUENCE(setupSeqPlayId, sActiveSequences[setupSeqPlayId].setupFadeTimer, 0, seqId);
                        Audio_SetSequenceFade(setupSeqPlayId, 1, 127, 0);
                        sActiveSequences[setupSeqPlayId].setupFadeTimer = 0;
                        break;
                    case SEQCMD_SUB_OP_SETUP_SET_FADE_TIMER:
                        sActiveSequences[seqPlayId].setupFadeTimer = val2;
                        break;
                }
            }
            sActiveSequences[seqPlayId].setupCmdNum = 0;
        }
    }
}

void Audio_SetDelayedSeqCmd(u32 seqCmd, u16 delay) {
    u8 opcode = (seqCmd >> 0x1C);

    sDelayedSeqCmds[opcode].seqData = seqCmd;
    sDelayedSeqCmds[opcode].timer = delay;
    sDelayedSeqCmdFlags |= 1 << opcode;
}

void Audio_UpdateDelayedSeqCmds(void) {
    u8 opcode = 0;
    u16 flag = 1;
    u16 delayedCmdFlags = sDelayedSeqCmdFlags;

    while (delayedCmdFlags) {
        if (delayedCmdFlags & flag) {
            if (sDelayedSeqCmds[opcode].timer != 0) {
                sDelayedSeqCmds[opcode].timer--;
            } else {
                Audio_QueueSeqCmd(sDelayedSeqCmds[opcode].seqData);
                sDelayedSeqCmdFlags ^= flag;
            }
            delayedCmdFlags ^= flag;
        }
        opcode++;
        flag <<= 1;
    }
}

u8 func_80018FA4(void) {
    if (D_800C5D58 != 0) {
        if (D_800C5D58 == 1) {
            if (func_8001ED34() == 1) {
                D_800C5D58 = 0;
                AUDIOCMD_SEQPLAYER_SET_IO(SEQ_PLAYER_SFX, 0, sSfxChannelLayout);
                func_8001DD40();
            }
        } else if (D_800C5D58 == 2) {
            while (func_8001ED34() != 1) {
                ;
            }
            D_800C5D58 = 0;
            AUDIOCMD_SEQPLAYER_SET_IO(SEQ_PLAYER_SFX, 0, sSfxChannelLayout);
            func_8001DD40();
        }
    }
    return D_800C5D58;
}

void Audio_ResetActiveSequences(void) {
    u8 i;

    for (i = 0; i < 4; i++) {
        sNumSeqRequests[i] = 0;
        sActiveSequences[i].seqId = SEQ_ID_NONE;
        sActiveSequences[i].prevSeqId = SEQ_ID_NONE;
        sActiveSequences[i].tempo.timer = 0;
        sActiveSequences[i].tempoOriginal = 0;
        sActiveSequences[i].tempoCmd = 0;
        sActiveSequences[i].channelPortMask = 0;
        sActiveSequences[i].setupCmdNum = 0;
        sActiveSequences[i].setupFadeTimer = 0;
        sActiveSequences[i].freqModChannelFlags = 0;
        sActiveSequences[i].volChannelFlags = 0;
        sActiveSequences[i].mainVolume.fadeMod[2] = 127;
    }
}

void Audio_ResetActiveSequencesAndVolume(void) {
    u8 i;

    for (i = 0; i < 4; i++) {
        sActiveSequences[i].mainVolume.mod = 1.0f;
        sActiveSequences[i].mainVolume.timer = 0;
        sActiveSequences[i].mainVolume.fadeActive = false;
        sActiveSequences[i].mainVolume.fadeMod[0] = 127;
        sActiveSequences[i].mainVolume.fadeMod[1] = 127;
        sActiveSequences[i].mainVolume.fadeMod[2] = 127;
    }
    Audio_ResetActiveSequences();
}

void Audio_SetSfxBanksMute(u16 muteFlags) {
    u8 i;

    for (i = 0; i < 5; i++) {
        sSfxBankMuted[i] = (muteFlags & 1) ? true : false;
        muteFlags = muteFlags >> 1;
    }
}

void Audio_ClearBGMMute(u8 channelIndex) {
    sChannelMuteFlags &= (1 << channelIndex) ^ 0xFFFF;
    if (sChannelMuteFlags == 0) {
        Audio_SetSequenceFade(SEQ_PLAYER_BGM, 2, 127, 15);
    }
}

void Audio_PlaySfx(u32 sfxId, f32* sfxSource, u8 token, f32* freqMod, f32* volMod, s8* reverbAdd) {
    if (sSfxBankMuted[SFX_BANK_SHIFT(sfxId)] == 0) {
        SfxRequest* request = &sSfxRequests[sSfxRequestWriteIndex];

        request->sfxId = sfxId;
        request->pos = sfxSource;
        request->token = token;
        request->freqMod = freqMod;
        request->volMod = volMod;
        request->reverbAdd = reverbAdd;
        sSfxRequestWriteIndex++;
    }
}

void Audio_RemoveMatchingSfxRequests(u8 aspect, SfxBankEntry* data) {
    u8 i = sSfxRequestReadIndex;

    for (i; i != sSfxRequestWriteIndex; i++) {
        s32 found = false;
        SfxRequest* request = &sSfxRequests[i];

        switch (aspect) {
            case 0:
                if (SFX_BANK_MASK(request->sfxId) == SFX_BANK_MASK(data->sfxId)) {
                    found = true;
                }
                break;
            case 1:
                if ((SFX_BANK_MASK(request->sfxId) == SFX_BANK_MASK(data->sfxId)) && (&request->pos[0] == data->xPos)) {
                    found = true;
                }
                break;
            case 2:
                if (&request->pos[0] == data->xPos) {
                    found = true;
                }
                break;
            case 3:
                if ((&request->pos[0] == data->xPos) && (request->sfxId == data->sfxId)) {
                    found = true;
                }
                break;
            case 4:
                if ((request->token == data->token) && (request->sfxId == data->sfxId)) {
                    found = true;
                }
                break;
            case 5:
                if (request->sfxId == data->sfxId) {
                    found = true;
                }
                break;
        }
        if (found) {
            request->sfxId = 0;
        }
    }
}

void Audio_ProcessSfxRequest(void) {
    SfxRequest* request = &sSfxRequests[sSfxRequestReadIndex];
    u8 next;
    s32 bankId;
    u8 evict;
    u32 sfxId;
    u8 count;
    SfxBankEntry* entry;

    if (request->sfxId == 0) {
        return;
    }
    bankId = SFX_BANK(request->sfxId);
    next = sSfxBanks[bankId][0].next;
    count = 0;
    while ((next != 0xFF) && (next != 0)) {
        if (request->pos == sSfxBanks[bankId][next].xPos) {
            if (request->sfxId == sSfxBanks[bankId][next].sfxId) {
                count = sUsedChannelsPerBank[sSfxChannelLayout][bankId];
            } else {
                if (count == 0) {
                    evict = next;
                    sfxId = sSfxBanks[bankId][next].sfxId;
                } else if (SFX_IMPORTANCE_MASK(sSfxBanks[bankId][next].sfxId) < SFX_IMPORTANCE_MASK(sfxId)) {
                    evict = next;
                    sfxId = sSfxBanks[bankId][next].sfxId;
                }
                count++;
                if (count == sUsedChannelsPerBank[sSfxChannelLayout][bankId]) {
                    if (SFX_IMPORTANCE_MASK(request->sfxId) >= SFX_IMPORTANCE_MASK(sfxId)) {
                        next = evict;
                    } else {
                        next = 0;
                    }
                }
            }
            if (count == sUsedChannelsPerBank[sSfxChannelLayout][bankId]) {
                if (SFX_BIT04(request->sfxId) || SFX_BIT13(request->sfxId) || (next == evict)) {
                    if (SFX_BIT12(sSfxBanks[bankId][next].sfxId) && (sSfxBanks[bankId][next].state != 1)) {
                        Audio_ClearBGMMute(sSfxBanks[bankId][next].channelIndex);
                    }
                    sSfxBanks[bankId][next].token = request->token;
                    sSfxBanks[bankId][next].sfxId = request->sfxId;
                    sSfxBanks[bankId][next].state = SFX_STATE(request->sfxId);
                    sSfxBanks[bankId][next].freshness = 2;
                    sSfxBanks[bankId][next].freqMod = request->freqMod;
                    sSfxBanks[bankId][next].volMod = request->volMod;
                    sSfxBanks[bankId][next].reverbAdd = request->reverbAdd;
                }
                next = 0;
            }
        }
        if (next != 0) {
            next = sSfxBanks[bankId][next].next;
        }
    }
    if ((sSfxBanks[bankId][sSfxBankFreeListStart[bankId]].next != 0xFF) && (next != 0)) {
        next = sSfxBankFreeListStart[bankId];
        entry = &sSfxBanks[bankId][next];
        entry->xPos = &request->pos[0];
        entry->yPos = &request->pos[1];
        entry->zPos = &request->pos[2];
        entry->token = request->token;
        entry->freqMod = request->freqMod;
        entry->volMod = request->volMod;
        entry->reverbAdd = request->reverbAdd;
        entry->sfxId = request->sfxId;
        entry->state = SFX_STATE(request->sfxId);
        entry->freshness = 2;

        entry->prev = sSfxBankListEnd[bankId];

        sSfxBanks[bankId][sSfxBankListEnd[bankId]].next = sSfxBankFreeListStart[bankId];
        sSfxBankListEnd[bankId] = sSfxBankFreeListStart[bankId];
        sSfxBankFreeListStart[bankId] = sSfxBanks[bankId][sSfxBankFreeListStart[bankId]].next;
        sSfxBanks[bankId][sSfxBankFreeListStart[bankId]].prev = 0xFF;

        entry->next = 0xFF;
    }
}

void Audio_RemoveSfxBankEntry(u8 bankId, u8 entryIndex) {
    SfxBankEntry* sfxBank = sSfxBanks[bankId];
    s32 pad;

    if (SFX_BIT12(sfxBank[entryIndex].sfxId)) {
        Audio_ClearBGMMute(sfxBank[entryIndex].channelIndex);
    }
    if (entryIndex == sSfxBankListEnd[bankId]) {
        sSfxBankListEnd[bankId] = sfxBank[entryIndex].prev;
    } else {
        sfxBank[sfxBank[entryIndex].next].prev = sfxBank[entryIndex].prev;
    }
    sfxBank[sfxBank[entryIndex].prev].next = sfxBank[entryIndex].next;
    sfxBank[entryIndex].next = sSfxBankFreeListStart[bankId];
    sfxBank[entryIndex].prev = 0xFF;

    sfxBank[sSfxBankFreeListStart[bankId]].prev = entryIndex;
    sSfxBankFreeListStart[bankId] = entryIndex;
    sfxBank[entryIndex].state = 0;
}

void Audio_ChooseActiveSfx(u8 bankId) {
    u8 numChosenSfx = 0;
    u8 numChannels;
    u8 k;
    u8 i;
    SfxBankEntry* entry;
    ActiveSfx* activeSfx;
    f32 maxRangeSq;
    f32 yScaled;
    ActiveSfx chosenSfx[8];
    u8 chosenEntryIndex;
    u8 j;
    u8 entryIndex;
    u8 needNewSfx;
    s32 importance;

    for (i = 0; i < 8; i++) {
        chosenSfx[i].priority = INT32_MAX;
        chosenSfx[i].entryIndex = 0xFF;
    }
    entryIndex = sSfxBanks[bankId]->next;
    k = 0;
    while (entryIndex != 0xFF) {
        if ((sSfxBanks[bankId][entryIndex].state == 1) &&
            (SFX_BIT04(sSfxBanks[bankId][entryIndex].sfxId) == SFX_BIT04(-1))) {
            sSfxBanks[bankId][entryIndex].freshness--;
        }
        if (sSfxBanks[bankId][entryIndex].freshness == 0) {
            Audio_RemoveSfxBankEntry(bankId, entryIndex);
        } else if (sSfxBanks[bankId][entryIndex].state != 0) {
            entry = &sSfxBanks[bankId][entryIndex];

            if (&entry->xPos[0] == gDefaultSfxSource) {
                entry->distance = 0.0f;
            } else {
                yScaled = *entry->yPos / 2.5f;
                entry->distance = SQ(*entry->xPos) + SQ(yScaled) + SQ(*entry->zPos);
            }
            importance = SFX_IMPORTANCE(entry->sfxId);
            if (SFX_BIT11(entry->sfxId)) {
                entry->priority = SQ(0xFF - importance) * SQ(76);
            } else {
                entry->priority = (u32) entry->distance + SQ(0xFF - importance) * SQ(76);
                if (*entry->zPos > 0.0f) {
                    entry->priority += (s32) (*entry->zPos * 6.0f);
                }
            }
            if (SFX_RANGE(entry->sfxId) != 0) {
                maxRangeSq = SQ(33000.0f) / SQ((s32) SFX_RANGE(entry->sfxId));
            } else {
                maxRangeSq = SQ(100000.0f);
            }
            if (entry->distance > maxRangeSq) {
                if (entry->state == 4) {
                    AUDIOCMD_CHANNEL_SET_IO(2, entry->channelIndex, 0, 0);
                    if (SFX_BIT04(entry->sfxId)) {
                        Audio_RemoveSfxBankEntry(bankId, entryIndex);
                        entryIndex = k;
                    }
                }
            } else {
                numChannels = sChannelsPerBank[sSfxChannelLayout][bankId];
                for (i = 0; i < numChannels; i++) {
                    if (chosenSfx[i].priority >= entry->priority) {
                        if (numChosenSfx < sChannelsPerBank[sSfxChannelLayout][bankId]) {
                            numChosenSfx++;
                        }
                        for (j = numChannels - 1; j > i; j--) {
                            chosenSfx[j].priority = chosenSfx[j - 1].priority;
                            chosenSfx[j].entryIndex = chosenSfx[j - 1].entryIndex;
                        }
                        chosenSfx[i].priority = entry->priority;
                        chosenSfx[i].entryIndex = entryIndex;
                        i = numChannels;
                    }
                }
            }
            k = entryIndex;
        }
        entryIndex = sSfxBanks[bankId][k].next;
    }

    for (i = 0; i < numChosenSfx; i++) {
        if (sSfxBanks[bankId][chosenSfx[i].entryIndex].state == 1) {
            sSfxBanks[bankId][chosenSfx[i].entryIndex].state = 2;
        } else if (sSfxBanks[bankId][chosenSfx[i].entryIndex].state == 4) {
            sSfxBanks[bankId][chosenSfx[i].entryIndex].state = 3;
        }
    }
    numChannels = sChannelsPerBank[sSfxChannelLayout][bankId];
    for (i = 0; i < numChannels; i++) {
        activeSfx = &sActiveSfx[bankId][i];
        needNewSfx = 0;
        if (activeSfx->entryIndex == 0xFF) {
            needNewSfx = 1;
        } else if (sSfxBanks[bankId][activeSfx->entryIndex].state == 4) {
            if (SFX_BIT04(sSfxBanks[bankId][activeSfx->entryIndex].sfxId)) {
                Audio_RemoveSfxBankEntry(bankId, activeSfx->entryIndex);
            } else {
                sSfxBanks[bankId][activeSfx->entryIndex].state = 1;
            }
            needNewSfx = 1;
        } else if (sSfxBanks[bankId][activeSfx->entryIndex].state == 0) {
            activeSfx->entryIndex = 0xFF;
            needNewSfx = 1;
        } else {
            for (j = 0; j < numChannels; j++) {
                if (activeSfx->entryIndex == chosenSfx[j].entryIndex) {
                    chosenSfx[j].entryIndex = 0xFF;
                    j = numChannels;
                }
            }
            numChosenSfx--;
        }

        if (needNewSfx == 1) {
            for (j = 0; j < numChannels; j++) {
                chosenEntryIndex = chosenSfx[j].entryIndex;
                if ((chosenEntryIndex != 0xFF) && (sSfxBanks[bankId][chosenEntryIndex].state != 3)) {
                    for (k = 0; k < numChannels; k++) {
                        if (chosenEntryIndex == sActiveSfx[bankId][k].entryIndex) {
                            needNewSfx = 0;
                            k = numChannels;
                        }
                    }
                    if (needNewSfx == 1) {
                        activeSfx->entryIndex = chosenEntryIndex;
                        chosenSfx[j].entryIndex = 0xFF;
                        j = numChannels + 1;
                        numChosenSfx--;
                    }
                }
            }
            if (j == numChannels) {
                activeSfx->entryIndex = 0xFF;
            }
        }
    }
}

void Audio_PlayActiveSfx(u8 bankId) {
    u8 i;

    for (i = 0; i < sChannelsPerBank[sSfxChannelLayout][bankId]; i++) {
        u8 entryIndex = sActiveSfx[bankId][i].entryIndex;

        if (entryIndex != 0xFF) {
            SfxBankEntry* entry = &sSfxBanks[bankId][entryIndex];
            SequenceChannel* channel = gSeqPlayers[SEQ_PLAYER_SFX].channels[sCurSfxPlayerChannelIndex];
            s32 pad;

            if (entry->state == 2) {
                entry->channelIndex = sCurSfxPlayerChannelIndex;
                if (SFX_BIT12(entry->sfxId)) {
                    sChannelMuteFlags |= 1 << sCurSfxPlayerChannelIndex;
                    Audio_SetSequenceFade(SEQ_PLAYER_BGM, 2, 64, 15);
                }
                Audio_SetSfxProperties(bankId, entryIndex, sCurSfxPlayerChannelIndex);
                AUDIOCMD_CHANNEL_SET_IO(SEQ_PLAYER_SFX, sCurSfxPlayerChannelIndex, 0, 1);
                AUDIOCMD_CHANNEL_SET_IO(SEQ_PLAYER_SFX, sCurSfxPlayerChannelIndex, 4, SFX_INDEX(entry->sfxId) & 0xFF);
                entry->state = 4;
            } else if ((u8) channel->seqScriptIO[7] == 0x80) {
                AUDIOCMD_CHANNEL_SET_IO(SEQ_PLAYER_SFX, sCurSfxPlayerChannelIndex, 7, 0);
                Audio_RemoveSfxBankEntry(bankId, entryIndex);
            } else if (entry->state == 3) {
                Audio_SetSfxProperties(bankId, entryIndex, sCurSfxPlayerChannelIndex);
                entry->state = 4;
            }
        }
        sCurSfxPlayerChannelIndex++;
    }
}

void Audio_KillSfxByBank(u8 bankId) {
    SfxBankEntry* entry;
    u8 next = sSfxBanks[bankId][0].next;

    SfxBankEntry cmp;

    while (next != 0xFF) {
        entry = &sSfxBanks[bankId][next];
        if (entry->state >= 3) {
            AUDIOCMD_CHANNEL_SET_IO(2, entry->channelIndex, 0, 0);
        }
        if (entry->state != 0) {
            Audio_RemoveSfxBankEntry(bankId, next);
        }
        next = sSfxBanks[bankId][0].next;
    }
    cmp.sfxId = bankId << 28;
    Audio_RemoveMatchingSfxRequests(0, &cmp);
}

void Audio_StopSfxByBankAndSource(u8 bankId, f32* sfxSource) {
    SfxBankEntry* entry;
    u8 curIndex = 0;
    u8 nextIndex = sSfxBanks[bankId][0].next;

    while (nextIndex != 0xFF) {
        entry = &sSfxBanks[bankId][nextIndex];
        if (entry->xPos == sfxSource) {
            if (entry->state >= 3) {
                AUDIOCMD_CHANNEL_SET_IO(SEQ_PLAYER_SFX, entry->channelIndex, 0, 0);
            }
            if (entry->state != 0) {
                Audio_RemoveSfxBankEntry(bankId, nextIndex);
            }
        } else {
            curIndex = nextIndex;
        }
        nextIndex = sSfxBanks[bankId][curIndex].next;
    }
}

void Audio_KillSfxByBankAndSource(u8 bankId, f32* sfxSource) {
    SfxBankEntry sp18;

    Audio_StopSfxByBankAndSource(bankId, sfxSource);
    sp18.sfxId = bankId << 0x1C;
    sp18.xPos = sfxSource;
    Audio_RemoveMatchingSfxRequests(1, &sp18);
}

void Audio_KillSfxBySource(f32* sfxSource) {
    u8 i;
    SfxBankEntry sp24;

    for (i = 0; i < 5; i++) {
        Audio_StopSfxByBankAndSource(i, sfxSource);
    }
    sp24.xPos = sfxSource;
    Audio_RemoveMatchingSfxRequests(2, &sp24);
}

void Audio_KillSfxBySourceAndId(f32* sfxSource, u32 sfxId) {
    u32 bankId = SFX_BANK(sfxId);
    u8 next = sSfxBanks[bankId][0].next;
    u8 current = 0;
    SfxBankEntry cmp;

    while (next != 0xFF) {
        if ((sSfxBanks[bankId][next].xPos == sfxSource) && (sSfxBanks[bankId][next].sfxId == sfxId)) {
            if (sSfxBanks[bankId][next].state >= 3) {
                AUDIOCMD_CHANNEL_SET_IO(SEQ_PLAYER_SFX, sSfxBanks[bankId][next].channelIndex, 0, 0);
            }
            if (sSfxBanks[bankId][next].state != 0) {
                Audio_RemoveSfxBankEntry(bankId, next);
            }
            next = 0xFF;
        } else {
            current = next;
        }
        if (next != 0xFF) {
            next = sSfxBanks[bankId][current].next;
        }
    }
    cmp.sfxId = sfxId;
    cmp.xPos = sfxSource;
    Audio_RemoveMatchingSfxRequests(3, &cmp);
}

void Audio_KillSfxByTokenAndId(u8 token, u32 sfxId) {
    u32 bankId = SFX_BANK(sfxId);
    u8 next = sSfxBanks[bankId][0].next;
    u8 current = 0;
    SfxBankEntry cmp;

    while (next != 0xFF) {
        if ((sSfxBanks[bankId][next].token == token) && (sSfxBanks[bankId][next].sfxId == sfxId)) {
            if (sSfxBanks[bankId][next].state >= 3) {
                AUDIOCMD_CHANNEL_SET_IO(SEQ_PLAYER_SFX, sSfxBanks[bankId][next].channelIndex, 0, 0);
            }
            if (sSfxBanks[bankId][next].state != 0) {
                Audio_RemoveSfxBankEntry(bankId, next);
            }
        } else {
            current = next;
        }
        if (next != 0xFF) {
            next = sSfxBanks[bankId][current].next;
        }
    }
    cmp.token = token;
    cmp.sfxId = sfxId;
    Audio_RemoveMatchingSfxRequests(4, &cmp);
}

void Audio_KillSfxById(u32 sfxId) {
    u32 bankId = SFX_BANK(sfxId);
    u8 next = sSfxBanks[bankId][0].next;
    u8 current = 0;
    SfxBankEntry cmp;

    while (next != 0xFF) {
        if (sfxId == sSfxBanks[bankId][next].sfxId) {
            if (sSfxBanks[bankId][next].state >= 3) {
                AUDIOCMD_CHANNEL_SET_IO(SEQ_PLAYER_SFX, sSfxBanks[bankId][next].channelIndex, 0, 0);
            }
            if (sSfxBanks[bankId][next].state != 0) {
                Audio_RemoveSfxBankEntry(bankId, next);
            }
        } else {
            current = next;
        }
        next = sSfxBanks[bankId][current].next;
    }
    cmp.sfxId = sfxId;
    Audio_RemoveMatchingSfxRequests(5, &cmp);
}

void Audio_ProcessSfxRequests(void) {
    while (sSfxRequestWriteIndex != sSfxRequestReadIndex) {
        Audio_ProcessSfxRequest();
        sSfxRequestReadIndex++;
    }
}

void Audio_SetSfxVolumeMod(u8 bankId, u8 target, u16 timer) {
    Modulation* scale = &sSfxVolumeMods[bankId];

    if (timer == 0) {
        timer++;
    }

    scale->target = target / 127.0f;
    scale->timer = timer;
    scale->step = (scale->value - scale->target) / timer;
}

void Audio_UpdateSfxVolumeMod(u8 bankId) {
    Modulation* scale = &sSfxVolumeMods[bankId];

    if (scale->timer != 0) {
        scale->timer--;
        if (scale->timer != 0) {
            scale->value -= scale->step;
        } else {
            scale->value = scale->target;
        }
    }
}

void Audio_PlayAllSfx(void) {
    u8 bankId;

    if (IS_SEQUENCE_CHANNEL_VALID(gSeqPlayers[SEQ_PLAYER_SFX].channels[0])) {
        sCurSfxPlayerChannelIndex = 0;
        for (bankId = 0; bankId < 5; bankId++) {
            Audio_ChooseActiveSfx(bankId);
            Audio_PlayActiveSfx(bankId);
            Audio_UpdateSfxVolumeMod(bankId);
        }
    }
}

void Audio_ResetSfx(void) {
    u8 i;
    u8 j;

    sSfxRequestWriteIndex = 0;
    sSfxRequestReadIndex = 0;
    sChannelMuteFlags = 0;
    for (i = 0; i < 5; i++) {
        sSfxBankListEnd[i] = 0;
        sSfxBankFreeListStart[i] = 1;
        sSfxBankUnused[i] = 0;
        sSfxBankMuted[i] = 0;
        sSfxVolumeMods[i].value = 1.0f;
        sSfxVolumeMods[i].timer = 0;
    }
    for (i = 0; i < 5; i++) {
        for (j = 0; j < 8; j++) {
            sActiveSfx[i][j].entryIndex = 0xFF;
        }
    }
    for (i = 0; i < 5; i++) {
        sSfxBanks[i][0].prev = 0xFF;
        sSfxBanks[i][0].next = 0xFF;
        for (j = 1; j < 19; j++) {
            sSfxBanks[i][j].prev = j - 1;
            sSfxBanks[i][j].next = j + 1;
        }
        sSfxBanks[i][j].prev = j - 1;
        sSfxBanks[i][j].next = 0xFF;
    }
}

void Audio_PlayVoice(s32 msgId) {
    sCurrentVoiceId = sNextVoiceId = msgId;
    sSetNextVoiceId = true;
}

void Audio_PlayVoiceWithoutBGM(u32 msgId) {
    sMuteBgmForVoice = true;
    Audio_SetSequenceFade(SEQ_PLAYER_BGM, 2, 64, 15);
    Audio_PlayVoice(msgId);
}

void Audio_UpdateVoice(void) {
    s8 voiceBank;
    u16 voiceId;
    u8 voiceIdHi;
    u8 voiceIdLo;

    if (sSetNextVoiceId) {
        voiceBank = sNextVoiceId / 1000;
        voiceId = sNextVoiceId % 1000;
        voiceIdHi = voiceId / 256;
        voiceIdLo = voiceId % 256;
        AUDIOCMD_CHANNEL_SET_IO(SEQ_PLAYER_VOICE, 15, 0, 1);
        AUDIOCMD_CHANNEL_SET_IO(SEQ_PLAYER_VOICE, 15, 4, voiceBank);
        AUDIOCMD_CHANNEL_SET_IO(SEQ_PLAYER_VOICE, 15, 5, voiceIdHi);
        AUDIOCMD_CHANNEL_SET_IO(SEQ_PLAYER_VOICE, 15, 6, voiceIdLo);
        sSetNextVoiceId = false;
    } else if ((sMuteBgmForVoice) && (Audio_GetCurrentVoice() == 0)) {
        Audio_SetSequenceFade(SEQ_PLAYER_BGM, 2, 127, 15);
        sMuteBgmForVoice = false;
    }
}

void Audio_ClearVoice(void) {
    sCurrentVoiceId = 0;
    sNextVoiceId = 1;
    sSetNextVoiceId = true;
}

s32 Audio_GetCurrentVoice(void) {
    if (!IS_SEQUENCE_CHANNEL_VALID(gSeqPlayers[SEQ_PLAYER_VOICE].channels[15])) {
        return 0;
    }
    if (gSeqPlayers[SEQ_PLAYER_VOICE].channels[15]->seqScriptIO[1] == 1) {
        if (sCurrentVoiceId < 4) {
            return 0;
        } else {
            return sCurrentVoiceId;
        }
    }
    return 0;
}

s32 Audio_GetCurrentVoiceStatus(void) {
    SequenceChannel* channel = gSeqPlayers[SEQ_PLAYER_VOICE].channels[15];
    SequenceLayer* layer = channel->layers[0];

    if (!IS_SEQUENCE_CHANNEL_VALID(channel) || (layer == NULL) || (channel->seqScriptIO[1] != 1)) {
        return 0;
    }
    if (layer->note != NULL) {
        if (layer != layer->note->playbackState.parentLayer) {
            return 2;
        } else {
            return 1;
        }
    }
    return 0;
}

void func_8001AF40(u8 unkVoiceParam) {
    D_800C7390 = unkVoiceParam;
}

void func_8001AF50(void) {
    if (D_800C7390 != 0xFF) {
        AUDIOCMD_CHANNEL_SET_IO(SEQ_PLAYER_VOICE, 14, 0, D_800C7390);
        D_800C7390 = 0xFF;
    }
}

void Audio_ResetPlayerFreqMods(void) {
    u8 i;
    u8 j;

    for (i = 0; i < 4; i++) {
        for (j = 0; j < 5; j++) {
            sPlayerNoise[i].freqMod[j].value = 1.0f;
            sPlayerNoise[i].freqMod[j].timer = 0;
            sPlayerNoise[i].freqMod[j].boost = 0;
            sPlayerNoise[i].freqMod[j].brake = 0;
        }
    }
}

void Audio_UpdateArwingNoise(u8 playerId) {
    f32 freqMod;
    u8 i;

    if (gPlayer[playerId].sfx.boost) {
        sPlayerNoise[playerId].freqMod[0].target = 1.5f;
        sPlayerNoise[playerId].freqMod[0].timer = 18;
        sPlayerNoise[playerId].freqMod[0].step =
            (sPlayerNoise[playerId].freqMod[0].target - sPlayerNoise[playerId].freqMod[0].value) / 18;
        sPlayerNoise[playerId].freqMod[0].boost = true;
    } else if (sPlayerNoise[playerId].freqMod[0].boost) {
        sPlayerNoise[playerId].freqMod[0].boost = false;
        sPlayerNoise[playerId].freqMod[0].timer = 1;
    }
    if (gPlayer[playerId].sfx.brake) {
        sPlayerNoise[playerId].freqMod[0].target = 0.65f;
        sPlayerNoise[playerId].freqMod[0].timer = 20;
        sPlayerNoise[playerId].freqMod[0].step =
            (sPlayerNoise[playerId].freqMod[0].target - sPlayerNoise[playerId].freqMod[0].value) / 20;
        sPlayerNoise[playerId].freqMod[0].brake = true;
    } else if (sPlayerNoise[playerId].freqMod[0].brake) {
        sPlayerNoise[playerId].freqMod[0].brake = false;
        sPlayerNoise[playerId].freqMod[0].timer = 1;
    }
    if ((gPlayer[playerId].sfx.bank != 0) && (gPlayer[playerId].sfx.zRot < 45.0f)) {
        sPlayerNoise[playerId].freqMod[2].target = 1.25f;
        sPlayerNoise[playerId].freqMod[2].timer = 10;
        sPlayerNoise[playerId].freqMod[2].step =
            (sPlayerNoise[playerId].freqMod[2].target - sPlayerNoise[playerId].freqMod[2].value) / 10;
    }
    if (gPlayer[playerId].sfx.roll != 0) {
        AUDIO_PLAY_SFX(0x09000012, gPlayer[playerId].sfx.srcPos, playerId);
        sPlayerNoise[playerId].freqMod[1].target = 1.65f;
        sPlayerNoise[playerId].freqMod[1].timer = 8;
        sPlayerNoise[playerId].freqMod[1].step =
            (sPlayerNoise[playerId].freqMod[1].target - sPlayerNoise[playerId].freqMod[1].value) / 8;
    }
    if (ABS(gPlayer[playerId].sfx.yVel) > 2.0f) {
        sPlayerNoise[playerId].freqMod[3].target = 1.25f;
        sPlayerNoise[playerId].freqMod[3].timer = 15;
        sPlayerNoise[playerId].freqMod[3].step =
            (sPlayerNoise[playerId].freqMod[3].target - sPlayerNoise[playerId].freqMod[3].value) / 15;
        sPlayerNoise[playerId].freqMod[3].boost = true;
    } else if (sPlayerNoise[playerId].freqMod[3].boost) {
        sPlayerNoise[playerId].freqMod[3].boost = false;
        sPlayerNoise[playerId].freqMod[3].timer = 1;
    }
    if (sPlayerNoise[playerId].freqMod[4].timer == 0) {
        sPlayerNoise[playerId].freqMod[4].target = (((f32) (gAudioRandom % 0x10000) / 32768.0) * 0.15f) + 1.0f - 0.15f;
        sPlayerNoise[playerId].freqMod[4].timer = 16 + (gAudioRandom >> 27);
        sPlayerNoise[playerId].freqMod[4].step =
            (sPlayerNoise[playerId].freqMod[4].target - sPlayerNoise[playerId].freqMod[3].value) /
            sPlayerNoise[playerId].freqMod[4].timer;
    }
    for (i = 0; i < 5; i++) {
        if (sPlayerNoise[playerId].freqMod[i].timer != 0) {
            sPlayerNoise[playerId].freqMod[i].timer--;
            sPlayerNoise[playerId].freqMod[i].value += sPlayerNoise[playerId].freqMod[i].step;
            if ((sPlayerNoise[playerId].freqMod[i].timer == 0) && (sPlayerNoise[playerId].freqMod[i].target != 1.0f)) {
                sPlayerNoise[playerId].freqMod[i].target = 1.0f;
                sPlayerNoise[playerId].freqMod[i].timer = D_800C5E58[i];
                sPlayerNoise[playerId].freqMod[i].step =
                    (1.0f - sPlayerNoise[playerId].freqMod[i].value) / D_800C5E58[i];
            }
        }
    }
    freqMod = 1.0f;
    for (i = 0; i < 5; i++) {
        freqMod *= sPlayerNoise[playerId].freqMod[i].value;
    }
    if (freqMod >= 4.0f) {
        freqMod = 4.0f;
    }
    sPlayerNoise[playerId].totalMod = freqMod;
}

void Audio_UpdateLandmasterNoise(u8 playerId) {
    f32 freqMod;
    u8 i;

    if ((gPlayer[playerId].sfx.bank != 0) && (gPlayer[playerId].sfx.zRot < 45.0f)) {
        sPlayerNoise[playerId].freqMod[2].timer = 10;
        sPlayerNoise[playerId].freqMod[2].target = 1.25f;
        sPlayerNoise[playerId].freqMod[2].step = (1.25f - sPlayerNoise[playerId].freqMod[2].value) / 10;
    }
    if (gPlayer[playerId].sfx.roll != 0) {
        sPlayerNoise[playerId].freqMod[1].timer = 8;
        sPlayerNoise[playerId].freqMod[1].target = 1.65f;
        sPlayerNoise[playerId].freqMod[1].step = (1.65f - sPlayerNoise[playerId].freqMod[1].value) / 8;
    }
    if (ABS(gPlayer[playerId].sfx.yVel) > 2.0f) {
        sPlayerNoise[playerId].freqMod[3].target = 1.25f;
        sPlayerNoise[playerId].freqMod[3].timer = 15;
        sPlayerNoise[playerId].freqMod[3].boost = true;
        sPlayerNoise[playerId].freqMod[3].step = (1.25f - sPlayerNoise[playerId].freqMod[3].value) / 15;
    } else if (sPlayerNoise[playerId].freqMod[3].boost) {
        sPlayerNoise[playerId].freqMod[3].boost = false;
        sPlayerNoise[playerId].freqMod[3].timer = 1;
    }
    for (i = 0; i < 5; i++) {
        if (sPlayerNoise[playerId].freqMod[i].timer != 0) {
            sPlayerNoise[playerId].freqMod[i].timer--;
            sPlayerNoise[playerId].freqMod[i].value += sPlayerNoise[playerId].freqMod[i].step;
            if ((sPlayerNoise[playerId].freqMod[i].timer == 0) && (sPlayerNoise[playerId].freqMod[i].target != 1.0f)) {
                sPlayerNoise[playerId].freqMod[i].target = 1.0f;
                sPlayerNoise[playerId].freqMod[i].timer = D_800C5E58[i];
                sPlayerNoise[playerId].freqMod[i].step =
                    (1.0f - sPlayerNoise[playerId].freqMod[i].value) / D_800C5E58[i];
            }
        }
    }
    freqMod = 1.0f;
    for (i = 0; i < 5; i++) {
        freqMod *= sPlayerNoise[playerId].freqMod[i].value;
    }
    if (ABS(gPlayer[playerId].pos.y) < 600.0f) {
        freqMod += (gPlayer[playerId].pos.y / 600.0f);
    } else {
        freqMod += 1.0f;
    }
    if (gPlayer[playerId].unk_0D0 > 25.0f) {
        freqMod += 0.5f;
    } else if (gPlayer[playerId].unk_0D0 < 5.0f) {
        freqMod -= 0.5f;
    } else {
        freqMod += (gPlayer[playerId].unk_0D0 - 15.0f) * 0.05f;
    }
    if (freqMod > 2.0f) {
        freqMod = 2.0f;
    }
    sPlayerNoise[playerId].totalMod = freqMod;
}

void Audio_UpdateBlueMarineNoise(u8 playerId) {
    u8 i;
    f32 freqMod;

    if ((gPlayer[playerId].sfx.bank != 0) && (gPlayer[playerId].sfx.zRot < 45.0f)) {
        sPlayerNoise[playerId].freqMod[2].timer = 10;
        sPlayerNoise[playerId].freqMod[2].target = 1.1f;
        sPlayerNoise[playerId].freqMod[2].step = (1.1f - sPlayerNoise[playerId].freqMod[2].value) / 10;
    }
    if (gPlayer[playerId].sfx.roll != 0) {
        AUDIO_PLAY_SFX(0x09000017, gPlayer[playerId].sfx.srcPos, playerId);
        sPlayerNoise[playerId].freqMod[1].timer = 8;
        sPlayerNoise[playerId].freqMod[1].target = 1.2f;
        sPlayerNoise[playerId].freqMod[1].step = (1.2f - sPlayerNoise[playerId].freqMod[1].value) / 8;
    }
    if (ABS(gPlayer[playerId].sfx.yVel) > 2.0f) {
        sPlayerNoise[playerId].freqMod[3].timer = 15;
        sPlayerNoise[playerId].freqMod[3].boost = true;
        sPlayerNoise[playerId].freqMod[3].target = 1.12f;
        sPlayerNoise[playerId].freqMod[3].step = (1.12f - sPlayerNoise[playerId].freqMod[3].value) / 15;
    } else if (sPlayerNoise[playerId].freqMod[3].boost) {
        sPlayerNoise[playerId].freqMod[3].boost = false;
        sPlayerNoise[playerId].freqMod[3].timer = 1;
    }
    for (i = 0; i < 5; i++) {
        if (sPlayerNoise[playerId].freqMod[i].timer != 0) {
            sPlayerNoise[playerId].freqMod[i].timer--;
            sPlayerNoise[playerId].freqMod[i].value += sPlayerNoise[playerId].freqMod[i].step;
            if ((sPlayerNoise[playerId].freqMod[i].timer == 0) && (sPlayerNoise[playerId].freqMod[i].target != 1.0f)) {
                sPlayerNoise[playerId].freqMod[i].target = 1.0f;
                sPlayerNoise[playerId].freqMod[i].timer = D_800C5E58[i];
                sPlayerNoise[playerId].freqMod[i].step =
                    (1.0f - sPlayerNoise[playerId].freqMod[i].value) / D_800C5E58[i];
            }
        }
    }
    freqMod = 1.0f;

    for (i = 0; i < 5; i++) {
        freqMod *= sPlayerNoise[playerId].freqMod[i].value;
    }
    if (freqMod > 2.0f) {
        freqMod = 2.0f;
    }
    sPlayerNoise[playerId].totalMod = freqMod;
}

void Audio_UpdatePlayerFreqMod(void) {
    u8 playerId;

    for (playerId = 0; playerId < 4; playerId++) {
        switch (sPlayerNoise[playerId].form) {
            case FORM_ARWING:
                Audio_UpdateArwingNoise(playerId);
                sPlayerNoise[playerId].totalMod *=
                    Audio_UpdateDopplerShift(gPlayer[playerId].sfx.srcPos, gPlayer[playerId].sfx.srcVel, 150.0f,
                                             &sPlayerNoise[playerId].dopplerShift);
                break;
            case FORM_LANDMASTER:
                Audio_UpdateLandmasterNoise(playerId);
                break;
            case FORM_BLUE_MARINE:
                Audio_UpdateBlueMarineNoise(playerId);
                break;
            case FORM_NONE:
                break;
        }
    }
}

void Audio_UpdatePlayerReverb(void) {
    u8 playerId;

    for (playerId = 0; playerId < 4; playerId++) {
        if ((sPlayerNoise[playerId].form == FORM_ARWING) && (gPlayer[playerId].sfx.levelType == LEVELTYPE_PLANET)) {
            if (gPlayer[playerId].pos.y < 150.0f) {
                sPlayerNoise[playerId].reverbAdd = (150.0f - gPlayer[playerId].pos.y) * 0.53f;
            } else {
                sPlayerNoise[playerId].reverbAdd = 0;
            }
        }
    }
}

void Audio_UpdatePlayerNoise(void) {
    Audio_UpdatePlayerFreqMod();
    Audio_UpdatePlayerReverb();
}

void Audio_ResetVoicesAndPlayers(void) {
    u8 playerId;

    Audio_ResetPlayerFreqMods();
    for (playerId = 0; playerId < 4; playerId++) {
        sPlayerNoise[playerId].form = FORM_NONE;
        sPlayerNoise[playerId].reverbAdd = 0;
        sPlayerNoise[playerId].totalMod = 1.0f;
        sPlayerNoise[playerId].dopplerShift = 1.0f;
        D_8014BA24[playerId] = 0;
        D_8014BA28[playerId] = 0;
    }
    sSfxFreqMod = 1.0f;
    sSfxVolMod = 1.0f;
    sNextVoiceId = 0;
    sCurrentVoiceId = 0;
    sSetNextVoiceId = 0;
    sMuteBgmForVoice = 0;
    sPlaylistIndex = 0xFF;
}

void Audio_ProcessPlaylist(void) {
    PlaylistCmd* cmd;
    u32 temp;
    u32 temp2;
    u32 temp1;
    u32 temp5;

    if (sPlaylistIndex != 0xFF) {
        if (sPlaylistTimer == 0) {
            cmd = &sPlaylists[sPlaylistIndex][sPlaylistCmdIndex];
            switch (cmd->opCode) {
                case 0:
                    Audio_PlaySequence(cmd->seqPlayId, cmd->seqId & 0xFF, 0, cmd->bgmParam);
                    sPlaylistTimer = sPlaylists[sPlaylistIndex][sPlaylistCmdIndex].timer;
                    sPlaylistCmdIndex++;
                    break;
                case 1:
                    SEQCMD_STOP_SEQUENCE_ALT(cmd->seqPlayId, cmd->fadeoutTime);
                    sPlaylistTimer = sPlaylists[sPlaylistIndex][sPlaylistCmdIndex].timer;
                    sPlaylistCmdIndex++;
                    break;
                case 2:
                    Audio_PlaySequenceDistorted(cmd->seqPlayId, cmd->seqId & 0xFF, 1121, 25, cmd->bgmParam);
                    sPlaylistTimer = sPlaylists[sPlaylistIndex][sPlaylistCmdIndex].timer;
                    sPlaylistCmdIndex++;
                    break;
                case 3:
                    Audio_PlayFanfare(cmd->seqId & 0xFF, 20, 10, 10);
                    sPlaylistTimer = sPlaylists[sPlaylistIndex][sPlaylistCmdIndex].timer;
                    sPlaylistCmdIndex++;
                    break;
                case 0xFF:
                    sPlaylistIndex = 0xFF;
                    break;
            }
        } else {
            sPlaylistTimer--;
        }
    }
}

void func_8001BFC0(f32* buffer0, f32* buffer1, s32 length, f32* buffer2) {
    f32 temp_ft0;
    f32 var_fs0;
    f32* buff0fromStart;
    f32* buf2half2;
    f32* buf2half3;
    f32* buff1half1;
    f32* buff0FromEnd;
    f32* buff1half2;
    s32 half;
    s32 i;
    s32 size;

    size = 1 << length;
    half = size >> 1;

    // Initialize buffer 2 if it is the wrong size for this calculation
    if (size != (s32) buffer2[0]) {
        buf2half2 = &buffer2[half];
        buf2half3 = &buf2half2[half];
        var_fs0 = 0.0f;
        temp_ft0 = D_PI / (2 * size);
        for (i = 0; i < half; i++) {
            *buf2half2++ = (__cosf(var_fs0) - __sinf(var_fs0)) * 0.707107f;
            *buf2half3++ = (__cosf(var_fs0) + __sinf(var_fs0)) * 0.707107f;
            var_fs0 += temp_ft0;
        }
    }

    buff0fromStart = buffer0;
    buff0FromEnd = &buffer0[size - 1];
    buff1half1 = buffer1;
    buff1half2 = &buffer1[half];

    // Copy even entries of buffer 0 into the first half of buffer 1. Copy odd entries into the second half in reverse
    // order
    for (i = 0; i < half; i++) {
        *buff1half1++ = *buff0fromStart;
        *buff1half2++ = *buff0FromEnd;
        buff0fromStart += 2;
        buff0FromEnd -= 2;
    }

    // reset the buffer pointers
    buff0FromEnd = &buffer0[size - 1];
    buff0fromStart = buffer0;
    buf2half2 = &buffer2[half];
    buf2half3 = &buf2half2[half];
    buff1half1 = buffer1;

    // FFT buffer 1 using buffer 2
    func_80008780(buffer1, length, buffer2);

    // handle i = 0 case
    buff0fromStart[0] = buff1half1[0];
    buff0fromStart[half] = buff1half1[half];

    // advance buffer pointers
    buf2half2++;
    buf2half3++;
    buff0fromStart++;
    buff1half1++;

    // seconnd half of buffer 1 in reverse order this time
    buff1half2 = &buffer1[size - 1];

    // convert to real amplitudes
    for (i = 1; i < half; i++) {
        *buff0fromStart++ = (*buf2half2 * *buff1half1) + (*buf2half3 * *buff1half2);
        *buff0FromEnd-- = (*buf2half3 * *buff1half1) - (*buf2half2 * *buff1half2);
        buff1half1++;
        buf2half3++;
        buf2half2++;
        buff1half2--;
    }
}

u8* Audio_UpdateFrequencyAnalysis(void) {
    s32 temp2;
    s32 i;
    s32 j;
    s32 k;
    s32 l;
    s32 m;
    s16* temp;
    f32* test;
    static s32 sFreqBins[] = {
        0,  1,  2,  3,  4,  6,  7,  8,   9,   10,  11,  12,  14,  16,  19,  22,
        26, 31, 37, 44, 54, 68, 88, 108, 138, 163, 188, 208, 222, 234, 242, 246,
    };
    static f32 sFreqGain = 17.0f;
    static f32 sFreqAmplitudes[32] = {
        0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
        0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
    };

    Audio_ProcessPlaylist();
    // clang-format off
    temp = gAiBuffers[gCurAiBuffIndex];\
    for(l = 0; l < 256; l++) {\
        D_80149AD8[l] = *temp++;
    }
    // clang-format on
    func_8001BFC0(D_80149AD8, D_80149ED8, 8, D_8014A2D8);
    j = 0;
    for (i = 0; i < 32; i++) {
        temp2 = sFreqBins[i] + 1;
        for (m = j; m < temp2; m++) {
            if (D_80149AD8[m] > 0.0f) {
                D_8014A8D8[i] += D_80149AD8[m];
            } else {
                D_8014A8D8[i] -= D_80149AD8[m];
            }
        }
        j = m;
    }
    for (k = 0; k < 32; k++) {
        D_8014A8D8[k] /= 8;
    }
    for (l = 0; l < 32; l++) {
        D_8014A8D8[l] = (D_8014A8D8[l] / 32768.0f) * sFreqGain;
        if (D_8014A8D8[l] > 1.0f) {
            D_8014A8D8[l] = 1.0f;
        }
        sFreqAmplitudes[l] = sFreqAmplitudes[l] * 0.75f + 0.25f * D_8014A8D8[l];
        D_8014A958[l] = sFreqAmplitudes[l] * 255.0f;
    }
    return D_8014A958;
}

void func_8001C8B8(u8 playerId) {
    u32 sfxId = 0x00000000;

    sPlayerNoise[playerId].form = gPlayer[playerId].sfx.form;
    Audio_ResetPlayerFreqMods();
    switch (sPlayerNoise[playerId].form) {
        case FORM_ARWING:
            if (gPlayer[playerId].sfx.levelType == LEVELTYPE_SPACE) {
                sfxId = 0x0100F020;
            } else {
                sfxId = 0x0100F005;
            }
            break;
        case FORM_LANDMASTER:
            sfxId = 0x0100F006;
            break;
        case FORM_BLUE_MARINE:
            sfxId = 0x0100F022;
            Audio_PlaySfx(0x1100802C, gPlayer[playerId].sfx.srcPos, playerId, &gDefaultMod, &gDefaultMod,
                          &sPlayerNoise[playerId].reverbAdd);
            break;
    }
    if (sfxId != 0) {
        Audio_PlaySfx(sfxId, gPlayer[playerId].sfx.srcPos, playerId, &sPlayerNoise[playerId].totalMod, &gDefaultMod,
                      &sPlayerNoise[playerId].reverbAdd);
    }
}

void func_8001CA24(u8 playerId) {
    u32 sfxId = 0x00000000;

    switch (sPlayerNoise[playerId].form) {
        case FORM_ARWING:
            if (gPlayer[playerId].sfx.levelType == LEVELTYPE_SPACE) {
                sfxId = 0x0100F020;
            } else {
                sfxId = 0x0100F005;
            }
            Audio_KillSfxBySourceAndId(gPlayer[playerId].sfx.srcPos, 0x1100000B);
            break;
        case FORM_LANDMASTER:
            sfxId = 0x0100F006;
            break;
        case FORM_BLUE_MARINE:
            sfxId = 0x0100F022;
            Audio_KillSfxBySourceAndId(gPlayer[playerId].sfx.srcPos, 0x1100802C);
            break;
    }
    sPlayerNoise[playerId].form = FORM_NONE;
    if (sfxId != 0) {
        Audio_KillSfxBySourceAndId(gPlayer[playerId].sfx.srcPos, sfxId);
    }
}

void func_8001CB80(u8 playerId, u8 arg1) {
    D_8014BA28[playerId] = sAudioFrameCounter;
    switch (arg1) {
        case 1:
            D_8014BA10[playerId] = 1.0f;
            D_8014BA20[playerId] = 1;
            break;
        case 2:
            D_8014BA10[playerId] = 1.5f;
            D_8014BA20[playerId] = 2;
            break;
        default:
        case 0:
            D_8014BA10[playerId] = 0.75f;
            D_8014BA20[playerId] = 0;
            break;
    }
    if (D_8014BA24[playerId] != 1) {
        Audio_PlaySfx(0x01008008, gPlayer[playerId].sfx.srcPos, playerId, &D_8014BA10[playerId], &gDefaultMod,
                      &sPlayerNoise[playerId].reverbAdd);
        D_8014BA24[playerId] = 1;
    }
}

void func_8001CCDC(u8 playerId, f32* sfxSource) {
    if (D_8014BA24[playerId] != 0) {
        switch (D_8014BA20[playerId]) {
            case 1:
                D_8014BA10[playerId] = 1.2f;
                break;
            case 2:
                D_8014BA10[playerId] = 1.5f;
                break;
            default:
            case 0:
                D_8014BA10[playerId] = 1.0f;
                break;
        }
        Audio_KillSfxBySourceAndId(gPlayer[playerId].sfx.srcPos, 0x01008008);
        Audio_PlaySfx(0x09001001, sfxSource, playerId, &D_8014BA10[playerId], &gDefaultMod,
                      &sPlayerNoise[playerId].reverbAdd);
        D_8014BA24[playerId] = 2;
    }
}

void func_8001CE28(u8 playerId, f32* sfxSource) {
    u32 sfxId;

    if (D_8014BA24[playerId] != 0) {
        switch (D_8014BA20[playerId]) {
            case 1:
                sfxId = 0x0903A00A;
                break;
            case 2:
                sfxId = 0x0901A00B;
                break;
            default:
            case 0:
                sfxId = 0x0901A009;
                break;
        }
        Audio_KillSfxByTokenAndId(playerId, 0x09001001);
        AUDIO_PLAY_SFX(sfxId, sfxSource, playerId);
        D_8014BA24[playerId] = 0;
    }
}

void func_8001CEFC(f32* sfxSource) {
    u32 sfxId = (gPlayer[0].sfx.levelType == LEVELTYPE_SPACE) ? 0x31000040 : 0x3100000C;

    AUDIO_PLAY_SFX(sfxId, sfxSource, 0);
}

void func_8001CF60(f32* sfxSource) {
    u32 sfxId = (gPlayer[0].sfx.levelType == LEVELTYPE_SPACE) ? 0x31000040 : 0x3100000C;

    Audio_KillSfxBySourceAndId(sfxSource, sfxId);
}

void func_8001CFA8(f32 arg0) {
    f32 var_fv0 = ABS(arg0);

    if (var_fv0 < 6.0f) {
        var_fv0 = 6.0f;
    } else if (var_fv0 > 30.0f) {
        var_fv0 = 30.0f;
    }

    sSfxFreqMod = ((var_fv0 - 18.0f) / 24.0f) + 1.0f;
}

void func_8001D034(f32* sfxSource, u32 sfxId, u8 semitones) {
    f32 semitoneMods[] = {
        1.0f, 1.059f, 1.122f, 1.189f, 1.26f, 1.335f, 1.414f, 1.498f, 1.587f, 1.682f, 1.782f, 1.888f, 2.0f,
    };

    if (semitones > 12) {
        semitones = 12;
    }
    func_8001D0B4(sfxSource, sfxId, semitoneMods[semitones]);
}

void func_8001D0B4(f32* sfxSource, u32 sfxId, f32 freqMod) {
    sSfxFreqMod = freqMod;
    Audio_PlaySfx(sfxId, sfxSource, 0, &sSfxFreqMod, &gDefaultMod, &gDefaultReverb);
}

void func_8001D10C(f32* sfxSource, u32 sfxId) {
    Audio_PlaySfx(sfxId, sfxSource, 0, &sSfxFreqMod, &sSfxVolMod, &gDefaultReverb);
}

void func_8001D15C(u8 arg0) {
    if (arg0 < 12) {
        sSfxFreqMod = (arg0 / 11.0f) + 0.5f;
    } else {
        sSfxFreqMod = 1.5f;
    }
}

void func_8001D1C8(u8 arg0, u8 arg1) {
    u8 temp1;
    u8 temp2;

    AUDIOCMD_CHANNEL_SET_IO(SEQ_PLAYER_SFX, 9, 2, 8 + (arg0 >> 2));
    AUDIOCMD_CHANNEL_SET_IO(SEQ_PLAYER_SFX, 10, 2, 8 + (arg0 >> 2));
    AUDIOCMD_CHANNEL_SET_IO(SEQ_PLAYER_SFX, 11, 2, 8 + (arg0 >> 2));
    AUDIOCMD_CHANNEL_SET_IO(SEQ_PLAYER_SFX, 9, 1, 19 - (arg1 * 3));
    AUDIOCMD_CHANNEL_SET_IO(SEQ_PLAYER_SFX, 10, 1, 19 - (arg1 * 3));
    AUDIOCMD_CHANNEL_SET_IO(SEQ_PLAYER_SFX, 11, 1, 19 - (arg1 * 3));
    temp1 = 68 - (arg0 >> 3);
    temp2 = 80 - (arg1 * 10);
    if (temp1 < temp2) {
        temp1 = temp2;
    }
    AUDIOCMD_CHANNEL_SET_IO(SEQ_PLAYER_SFX, 9, 3, temp1);
    AUDIOCMD_CHANNEL_SET_IO(SEQ_PLAYER_SFX, 10, 3, temp1);
    AUDIOCMD_CHANNEL_SET_IO(SEQ_PLAYER_SFX, 11, 3, temp1);
}

void Audio_PlayEventSfx(f32* sfxSource, u16 arg1) {
    if ((D_800C5E88[arg1] & 0xF0000000) != 0x40000000) {
        AUDIO_PLAY_SFX(D_800C5E88[arg1], sfxSource, 0);
    } else {
        AUDIO_PLAY_SFX(D_800C5E88[arg1], gDefaultSfxSource, 0);
    }
}

void Audio_StopEventSfx(f32* sfxSource, u16 arg1) {
    if ((D_800C5E88[arg1] & 0xF0000000) != 0x40000000) {
        Audio_KillSfxBySourceAndId(sfxSource, D_800C5E88[arg1]);
    } else {
        Audio_KillSfxBySourceAndId(gDefaultSfxSource, D_800C5E88[arg1]);
    }
}

void Audio_SetBaseSfxReverb(s8 reverb) {
    sBaseReverb = reverb;
}

void Audio_SetBgmParam(s8 bgmParam) {
    SEQCMD_SET_SEQPLAYER_IO(SEQ_PLAYER_BGM, 0, bgmParam);
}

void Audio_PlaySequence(u8 seqPlayId, u16 seqId, u8 fadeinTime, u8 bgmParam) {
    SEQCMD_SET_SEQPLAYER_IO(seqPlayId, 0, bgmParam);
    SEQCMD_PLAY_SEQUENCE(seqPlayId, fadeinTime, 0, seqId);
}

void Audio_PlayFanfare(u16 seqId, u8 bgmVolume, u8 bgmFadeoutTime, u8 bgmFadeinTime) {
    if (Audio_GetActiveSeqId(SEQ_PLAYER_BGM) != SEQ_ID_DEATH) {
        Audio_SetSequenceFade(SEQ_PLAYER_BGM, 1, bgmVolume, bgmFadeoutTime);
        SEQCMD_SETUP_RESTORE_SEQPLAYER_VOLUME(SEQ_PLAYER_FANFARE, SEQ_PLAYER_BGM, bgmFadeinTime);
        SEQCMD_PLAY_SEQUENCE(SEQ_PLAYER_FANFARE, 0, 0, seqId);
    }
}

void func_8001D520(void) {
    u8 i;

    if (sNewAudioSpecId == 24) {
        Audio_ClearVoice();
        func_8001D6DC(0);
        AUDIO_PLAY_SFX(0x0903F004, gDefaultSfxSource, 4);
        SEQCMD_SET_SEQPLAYER_VOLUME(SEQ_PLAYER_BGM, 5, 30);
        SEQCMD_SETUP_RESTORE_SEQPLAYER_VOLUME(SEQ_PLAYER_FANFARE, SEQ_PLAYER_BGM, 30);
        SEQCMD_PLAY_SEQUENCE(SEQ_PLAYER_FANFARE, 0, 0, 39);
    } else {
        for (i = 0; i < 5; i++) {
            Audio_KillSfxByBank(i);
        }
        AUDIOCMD_GLOBAL_UNMUTE(true);
        AUDIO_PLAY_SFX(0x0903F004, gDefaultSfxSource, 4);
        SEQCMD_STOP_SEQUENCE(SEQ_PLAYER_BGM, 0);
        SEQCMD_STOP_SEQUENCE(SEQ_PLAYER_FANFARE, 0);
        SEQCMD_PLAY_SEQUENCE(SEQ_PLAYER_BGM, 0, 0, 39);
    }
}

void func_8001D638(u8 arg0) {
    if (arg0) {
        AUDIO_PLAY_SFX(0x4900F000, gDefaultSfxSource, 4);
        AUDIOCMD_GLOBAL_MUTE();
    } else {
        AUDIO_PLAY_SFX(0x4900F000, gDefaultSfxSource, 4);
        AUDIOCMD_GLOBAL_UNMUTE(false);
    }
}

void func_8001D6DC(u8 arg0) {
    if (arg0) {
        AUDIO_PLAY_SFX(0x49000019, gDefaultSfxSource, 4);
        AUDIOCMD_GLOBAL_MUTE();
    } else {
        AUDIO_PLAY_SFX(0x4900101A, gDefaultSfxSource, 4);
        AUDIOCMD_GLOBAL_UNMUTE(false);
    }
}

void func_8001D780(u8 audioType) {
    s8 volume = ((sVolumeSettings[audioType] * 127) / 99) % 128U;
    u8 i;

    switch (audioType) {
        case 0:
            Audio_SetSequenceFade(SEQ_PLAYER_BGM, 0, volume, 1);
            Audio_SetSequenceFade(SEQ_PLAYER_FANFARE, 0, volume, 1);
            break;
        case 2:
            for (i = 0; i < 15; i++) {
                AUDIOCMD_CHANNEL_SET_VOL(SEQ_PLAYER_SFX, (u32) i, volume / 127.0f);
            }
            break;
        case 1:
            AUDIOCMD_CHANNEL_SET_VOL(SEQ_PLAYER_VOICE, 15, volume / 127.0f);
            break;
    }
}

void func_8001D8A8(u8 audioType, u8 volume) {
    if (volume > 99) {
        volume = 99;
    }
    sVolumeSettings[audioType] = volume;
    func_8001D780(audioType);
}

void Audio_PlaySoundTest(u8 enable) {
    switch (enable) {
        case false:
            AUDIO_PLAY_BGM(SEQ_ID_MENU);
            Audio_PlayVoice(1);
            Audio_KillSfxById(0x0100001F);
            Audio_KillSfxById(0x0100F005);
            break;
        case true:
            AUDIO_PLAY_BGM(SEQ_ID_VERSUS);
            Audio_PlayVoice(2);
            AUDIO_PLAY_SFX(0x0100001F, gDefaultSfxSource, 0);
            AUDIO_PLAY_SFX(0x0100F005, gDefaultSfxSource, 0);
            break;
    }
}

void Audio_PlaySequenceDistorted(u8 seqPlayId, u16 seqId, u16 distortion, u8 fadeinTime, u8 unused) {
    u8 tempoDistortion = (distortion / 10);

    Audio_PlaySequence(seqPlayId, seqId & ~0x8000, 0, -1);
    SEQCMD_SET_SEQPLAYER_FREQ(seqPlayId, fadeinTime, distortion);
    SEQCMD_SCALE_TEMPO(seqPlayId, fadeinTime, tempoDistortion);
}

void Audio_PlaySoundTestTrack(u8 trackNumber) {
    u16 sp26;
    u8 sp25;

    if ((trackNumber >= 45) && (trackNumber < 50)) {
        SEQCMD_STOP_SEQUENCE(SEQ_PLAYER_BGM, 1);
        SEQCMD_STOP_SEQUENCE(SEQ_PLAYER_FANFARE, 1);
        sPlaylistIndex = trackNumber - 45;
        sPlaylistCmdIndex = 0;
        sPlaylistTimer = 0;
    } else if (trackNumber >= 50) {
        AUDIO_PLAY_SFX(0x4900100A, gDefaultSfxSource, 4);
    } else {
        sPlaylistIndex = 0xFF;
        sp26 = sSoundTestTracks[trackNumber].seqId & 0xFF;
        sp25 = sSoundTestTracks[trackNumber].bgmParam;
        SEQCMD_STOP_SEQUENCE(D_800C5E70 ^ 1, 5);
        Audio_PlaySequence(D_800C5E70, sp26, 0, sp25);
        D_800C5E70 ^= 1;
    }
}

void Audio_FadeOutAll(u8 fadeoutTime) {
    SEQCMD_SET_SEQPLAYER_VOLUME(SEQ_PLAYER_BGM, fadeoutTime, 0);
    SEQCMD_SET_SEQPLAYER_VOLUME(SEQ_PLAYER_FANFARE, fadeoutTime, 0);
    SEQCMD_SET_SEQPLAYER_VOLUME(SEQ_PLAYER_SFX, fadeoutTime, 0);
    SEQCMD_SET_SEQPLAYER_VOLUME(SEQ_PLAYER_VOICE, fadeoutTime, 0);
}

void Audio_KillAllSfx(void) {
    u8 i;

    for (i = 0; i < 5; i++) {
        Audio_KillSfxByBank(i);
    }
}

void Audio_SetAudioSpec(u8 unused, u16 specParam) {
    u8 sfxChannelLayout = ((specParam & 0xFF00) >> 8);
    u8 specId = specParam & 0xFF;

    SEQCMD_RESET_AUDIO_HEAP(sfxChannelLayout, specId);
}

// unused
void Audio_PlayBgm(u16 seqId) {
    SEQCMD_PLAY_SEQUENCE(SEQ_PLAYER_BGM, 1, 0, seqId);
}

void Audio_InitSounds(void) {
    Audio_ResetVoicesAndPlayers();
    Audio_ResetSfxChannelState();
    Audio_ResetActiveSequencesAndVolume();
    Audio_ResetSfx();
    Audio_StartSequence(SEQ_PLAYER_VOICE, SEQ_ID_VOICE, 0xFF, 1);
    Audio_StartSequence(SEQ_PLAYER_SFX, SEQ_ID_SFX, 0xFF, 10);
}

void func_8001DD40(void) {
    s32 pad1;
    s32 pad2;
    u16 sp1E = 1;

    Audio_StartSequence(SEQ_PLAYER_VOICE, SEQ_ID_VOICE, 0xFF, 1);
    if (sNewAudioSpecId == 12) {
        sp1E = 360;
    } else if (sNewAudioSpecId < 23) {
        sp1E = 90;
    }
    Audio_StartSequence(SEQ_PLAYER_SFX, SEQ_ID_SFX, 0xFF, sp1E);
    func_80017494();
    func_80017550();
    SEQCMD_SET_SEQPLAYER_VOLUME(SEQ_PLAYER_SFX, 0, 127);
    SEQCMD_SET_SEQPLAYER_VOLUME(SEQ_PLAYER_VOICE, 0, 127);
    AudioThread_ScheduleProcessCmds();
    AUDIOCMD_GLOBAL_STOP_AUDIOCMDS();
    AUDIOCMD_GLOBAL_STOP_AUDIOCMDS();
    AUDIOCMD_GLOBAL_STOP_AUDIOCMDS();
    func_8001D780(0);
    func_8001D780(2);
    func_8001D780(1);
}

void func_8001DE1C(u8 oldSpecId) {
    if (oldSpecId == 16) {
        if ((sNewAudioSpecId == 22) || (sNewAudioSpecId == 23)) {
            D_800C5D58 = 2;
        }
    } else if ((oldSpecId == 28) && (sNewAudioSpecId == 23)) {
        D_800C5D58 = 2;
    } else {
        D_800C5D58 = 1;
    }
    AUDIOCMD_GLOBAL_UNMUTE(true);
    Audio_ResetVoicesAndPlayers();
    Audio_ResetSfxChannelState();
    Audio_ResetActiveSequences();
    Audio_ResetSfx();
}

void Audio_Update(void) {
    if (func_80018FA4() == 0) {
        Audio_ProcessSfxRequests();
        Audio_ProcessSeqCmds();
        Audio_PlayAllSfx();
        Audio_UpdatePlayerNoise();
        Audio_UpdateVoice();
        func_8001AF50();
        Audio_UpdateActiveSequences();
        Audio_UpdateDelayedSeqCmds();
        AudioThread_ScheduleProcessCmds();
    }
    sAudioFrameCounter++;
}
