Audio Sfx (code_801A5BD0 and selected sfx functions in code_8019AF00.c) OK and Documented (#798)

* Rename functions

* code_801A5BD0 OK

* PR 1, improve spacing

* Rename unused struct

* Rename Sfx Variables

* PR Feedback, update names

* Add comment

* cleanup vars

* Fix merge

* Rework documentation, include more functions in sfx system

* PR suggestions

* fix AudioSfx_MuteBanks

* missed enum

* more cleanup

* more suggestions
This commit is contained in:
engineer124
2022-08-15 14:39:57 -04:00
committed by GitHub
parent 0082c299c6
commit 82fe521721
47 changed files with 2739 additions and 1284 deletions
+2 -2
View File
@@ -1208,7 +1208,7 @@ void AudioLoad_Init(void* heap, size_t heapSize) {
gAudioContext.refreshRate = 60;
}
Audio_InitMesgQueues();
AudioThread_InitMesgQueues();
for (i = 0; i < ARRAY_COUNT(gAudioContext.aiBufLengths); i++) {
gAudioContext.aiBufLengths[i] = 0xA0;
@@ -1217,7 +1217,7 @@ void AudioLoad_Init(void* heap, size_t heapSize) {
gAudioContext.totalTaskCount = 0;
gAudioContext.rspTaskIndex = 0;
gAudioContext.curAiBuffferIndex = 0;
gAudioContext.soundMode = AUDIO_MODE_STEREO;
gAudioContext.soundMode = SOUNDMODE_STEREO;
gAudioContext.curTask = NULL;
gAudioContext.rspTask[0].task.t.dataSize = 0;
gAudioContext.rspTask[1].task.t.dataSize = 0;
+3 -3
View File
@@ -34,7 +34,7 @@ void AudioPlayback_InitNoteSub(Note* note, NoteSubEu* sub, NoteSubAttributes* at
sub->bitField0.stereoStrongLeft = false;
sub->bitField0.stereoHeadsetEffects = stereoData.stereoHeadsetEffects;
sub->bitField0.usesHeadsetPanEffects = stereoData.usesHeadsetPanEffects;
if (stereoHeadsetEffects && gAudioContext.soundMode == AUDIO_MODE_HEADSET) {
if (stereoHeadsetEffects && gAudioContext.soundMode == SOUNDMODE_HEADSET) {
smallPanIndex = pan >> 1;
if (smallPanIndex > 0x3F) {
smallPanIndex = 0x3F;
@@ -46,7 +46,7 @@ void AudioPlayback_InitNoteSub(Note* note, NoteSubEu* sub, NoteSubAttributes* at
volLeft = gHeadsetPanVolume[pan];
volRight = gHeadsetPanVolume[0x7F - pan];
} else if (stereoHeadsetEffects && gAudioContext.soundMode == AUDIO_MODE_STEREO) {
} else if (stereoHeadsetEffects && gAudioContext.soundMode == SOUNDMODE_STEREO) {
strongLeft = strongRight = false;
sub->headsetPanRight = 0;
sub->headsetPanLeft = 0;
@@ -80,7 +80,7 @@ void AudioPlayback_InitNoteSub(Note* note, NoteSubEu* sub, NoteSubAttributes* at
break;
}
} else if (gAudioContext.soundMode == AUDIO_MODE_MONO) {
} else if (gAudioContext.soundMode == SOUNDMODE_MONO) {
sub->bitField0.stereoHeadsetEffects = false;
sub->bitField0.usesHeadsetPanEffects = false;
volLeft = 0.707f; // approx 1/sqrt(2)
+1 -1
View File
@@ -1633,7 +1633,7 @@ void AudioSeq_SequenceChannelProcessScript(SequenceChannel* channel) {
break;
case 0xA8: // channel: random range large (only cmd that differs from OoT)
rand = Audio_NextRandom();
rand = AudioThread_NextRandom();
channel->unk_22 = (cmdArgs[0] == 0) ? (rand & 0xFFFF) : (rand % cmdArgs[0]);
channel->unk_22 += cmdArgs[1];
temp2 = (channel->unk_22 / 0x100) + 0x80;
+4 -4
View File
@@ -1,9 +1,9 @@
#include "global.h"
#define DEFINE_SFX(_0, importance, distParam, randParam, flags2, flags1) \
{ importance, flags2, \
((((distParam) << SFX_PARAM_01_SHIFT) & SFX_PARAM_01_MASK) | \
(((randParam) << SFX_PARAM_67_SHIFT) & SFX_PARAM_67_MASK) | (flags1)) },
#define DEFINE_SFX(_0, importance, distParam, randParam, flags2, flags1) \
{ importance, flags2, \
((((distParam) << SFX_PARAM_DIST_RANGE_SHIFT) & SFX_PARAM_DIST_RANGE_MASK) | \
(((randParam) << SFX_PARAM_RAND_FREQ_RAISE_SHIFT) & SFX_PARAM_RAND_FREQ_RAISE_MASK) | (flags1)) },
SfxParams sEnemyBankParams[] = {
#include "tables/sfx/enemybank_table.h"
+5 -5
View File
@@ -16,13 +16,13 @@
#pragma GLOBAL_ASM("asm/non_matchings/code/code_80192BE0/func_80193858.s")
#pragma GLOBAL_ASM("asm/non_matchings/code/code_80192BE0/func_8019387C.s")
#pragma GLOBAL_ASM("asm/non_matchings/code/code_80192BE0/AudioThread_QueueCmdS32.s")
#pragma GLOBAL_ASM("asm/non_matchings/code/code_80192BE0/Audio_QueueCmdS8.s")
#pragma GLOBAL_ASM("asm/non_matchings/code/code_80192BE0/AudioThread_QueueCmdS8.s")
#pragma GLOBAL_ASM("asm/non_matchings/code/code_80192BE0/func_801938D0.s")
#pragma GLOBAL_ASM("asm/non_matchings/code/code_80192BE0/func_80193900.s")
#pragma GLOBAL_ASM("asm/non_matchings/code/code_80192BE0/AudioThread_ScheduleProcessCmds.s")
#pragma GLOBAL_ASM("asm/non_matchings/code/code_80192BE0/func_80193990.s")
@@ -76,6 +76,6 @@
#pragma GLOBAL_ASM("asm/non_matchings/code/code_80192BE0/func_80194568.s")
#pragma GLOBAL_ASM("asm/non_matchings/code/code_80192BE0/Audio_NextRandom.s")
#pragma GLOBAL_ASM("asm/non_matchings/code/code_80192BE0/AudioThread_NextRandom.s")
#pragma GLOBAL_ASM("asm/non_matchings/code/code_80192BE0/Audio_InitMesgQueues.s")
#pragma GLOBAL_ASM("asm/non_matchings/code/code_80192BE0/AudioThread_InitMesgQueues.s")
+603 -72
View File
@@ -18,15 +18,15 @@ typedef struct {
} SfxSettings; // size = 0x9
typedef struct {
/* 0x0 */ f32 vol;
/* 0x0 */ f32 volume;
/* 0x4 */ f32 freqScale;
/* 0x8 */ s8 reverb;
/* 0x9 */ s8 panSigned;
/* 0xA */ s8 stereoBits;
/* 0xB */ u8 filter;
/* 0xC */ u8 unk_0C;
/* 0xD */ u8 unk_0D;
} SfxPlayerState; // size = 0xE
/* 0xC */ u8 combFilterGain;
/* 0xD */ u8 zVolume;
} SfxChannelState; // size = 0xE
typedef enum {
/* 0x0 */ SFX_CHANNEL_PLAYER0, // SfxPlayerBank
@@ -91,7 +91,7 @@ f32* sSfxVolumeCur;
f32 sSfxVolumeTarget;
f32 sSfxVolumeRate;
u16 sSceneSeqId1;
SfxPlayerState sSfxChannelState[16];
SfxChannelState sSfxChannelState[16];
// Sequence bss
u8 D_801FD3A8;
@@ -154,7 +154,8 @@ OcarinaNote sScarecrowsLongSongSecondNote;
u16 sCustomSequencePc;
// Sfx Data
u8 D_801D6600[] = {
// If the Sfx Bank has more than 255 values (max value of u8)
u8 gIsLargeSfxBank[] = {
true, false, true, true, false, false, true,
};
u8 D_801D6608[] = {
@@ -192,7 +193,7 @@ u8 sEnterGanonsTowerTimer = 0;
u16 sSfxVolumeDuration = 0;
// System Data
s8 sAudioFileSelectSetting = AUDIO_FS_STEREO;
s8 sSoundMode = SOUNDMODE_STEREO;
s8 sAudioIsWindowOpen = false;
s8 sAudioCutsceneFlag = false;
s8 sSpecReverb = 0;
@@ -2495,7 +2496,7 @@ void AudioOcarina_PlayControllerInput(u8 isOcarinaSfxSuppressedWhenCancelled) {
// Add vibrato of the ocarina note based on the x control stick
sCurOcarinaVibrato = ABS_ALT(sOcarinaInputStickRel.x) >> 2;
// Sets vibrato to io port 6
Audio_QueueCmdS8(0x6 << 24 | SEQ_PLAYER_SFX << 16 | SFX_CHANNEL_OCARINA << 8 | 6, sCurOcarinaVibrato);
AudioThread_QueueCmdS8(0x6 << 24 | SEQ_PLAYER_SFX << 16 | SFX_CHANNEL_OCARINA << 8 | 6, sCurOcarinaVibrato);
} else {
// no bending or vibrato for recording state OCARINA_RECORD_SCARECROW_SPAWN
sCurOcarinaBendIndex = 0;
@@ -2507,15 +2508,16 @@ void AudioOcarina_PlayControllerInput(u8 isOcarinaSfxSuppressedWhenCancelled) {
if ((sCurOcarinaPitch != OCARINA_PITCH_NONE) && (sPrevOcarinaPitch != sCurOcarinaPitch)) {
// Sets ocarina instrument Id to io port 7, which is used
// as an index in seq 0 to get the true instrument Id
Audio_QueueCmdS8(0x6 << 24 | SEQ_PLAYER_SFX << 16 | SFX_CHANNEL_OCARINA << 8 | 7, sOcarinaInstrumentId - 1);
AudioThread_QueueCmdS8(0x6 << 24 | SEQ_PLAYER_SFX << 16 | SFX_CHANNEL_OCARINA << 8 | 7,
sOcarinaInstrumentId - 1);
// Sets pitch to io port 5
Audio_QueueCmdS8(0x6 << 24 | SEQ_PLAYER_SFX << 16 | SFX_CHANNEL_OCARINA << 8 | 5, sCurOcarinaPitch);
Audio_PlaySfxGeneral(NA_SE_OC_OCARINA, &gSfxDefaultPos, 4, &sCurOcarinaBendFreq, &sDefaultOcarinaVolume,
&gSfxDefaultReverb);
AudioThread_QueueCmdS8(0x6 << 24 | SEQ_PLAYER_SFX << 16 | SFX_CHANNEL_OCARINA << 8 | 5, sCurOcarinaPitch);
AudioSfx_PlaySfx(NA_SE_OC_OCARINA, &gSfxDefaultPos, 4, &sCurOcarinaBendFreq, &sDefaultOcarinaVolume,
&gSfxDefaultReverb);
} else if ((sPrevOcarinaPitch != OCARINA_PITCH_NONE) && (sCurOcarinaPitch == OCARINA_PITCH_NONE) &&
!isOcarinaSfxSuppressedWhenCancelled) {
// Stops ocarina sound when transitioning from playing to not playing a note
Audio_StopSfxById(NA_SE_OC_OCARINA);
AudioSfx_StopById(NA_SE_OC_OCARINA);
}
}
}
@@ -2540,10 +2542,10 @@ void AudioOcarina_ResetAndMute(void) {
sOcarinaInputButtonStart = 0xFFFF;
AudioOcarina_PlayControllerInput(false);
Audio_StopSfxById(NA_SE_OC_OCARINA);
AudioSfx_StopById(NA_SE_OC_OCARINA);
if (gAudioSpecId != 12) {
Audio_SetSfxBanksMute(0);
AudioSfx_MuteBanks(0);
}
sPlaybackState = 0;
@@ -2553,7 +2555,7 @@ void AudioOcarina_ResetAndMute(void) {
sOcarinaFlags = 0;
// return to full volume for both bgm players after ocarina is finished
Audio_ClearFlagForBgmVolumeLow(SFX_CHANNEL_OCARINA);
AudioSfx_RestoreBgmVolume(SFX_CHANNEL_OCARINA);
// return to full volume for all sfx channels except system & ocarina banks
Audio_SetSfxVolumeExceptSystemAndOcarinaBanks(0x7F);
}
@@ -2602,7 +2604,7 @@ u32 AudioOcarina_SetInstrument(u8 ocarinaInstrumentId) {
// lowers volume of all sfx channels except system & ocarina banks
Audio_SetSfxVolumeExceptSystemAndOcarinaBanks(0x40);
// lowers volume of bgm players while playing ocarina
Audio_SetFlagForBgmVolumeLow(SFX_CHANNEL_OCARINA);
AudioSfx_LowerBgmVolume(SFX_CHANNEL_OCARINA);
}
}
}
@@ -2612,7 +2614,7 @@ void AudioOcarina_SetPlaybackSong(s8 songIndexPlusOne, u8 playbackState) {
if (songIndexPlusOne == 0) {
sPlaybackState = 0;
Audio_StopSfxById(NA_SE_OC_OCARINA);
AudioSfx_StopById(NA_SE_OC_OCARINA);
return;
}
@@ -2700,7 +2702,7 @@ void AudioOcarina_PlaybackSong(void) {
sPlaybackStaffPos = 0;
sPlaybackPitch = OCARINA_PITCH_NONE;
} else {
Audio_StopSfxById(NA_SE_OC_OCARINA);
AudioSfx_StopById(NA_SE_OC_OCARINA);
}
return;
} else {
@@ -2716,7 +2718,7 @@ void AudioOcarina_PlaybackSong(void) {
// Update vibrato
sNotePlaybackVibrato = sPlaybackSong[sPlaybackNotePos].vibrato;
// Sets vibrato to io port 6
Audio_QueueCmdS8(0x6 << 24 | SEQ_PLAYER_SFX << 16 | SFX_CHANNEL_OCARINA << 8 | 6, sNotePlaybackVibrato);
AudioThread_QueueCmdS8(0x6 << 24 | SEQ_PLAYER_SFX << 16 | SFX_CHANNEL_OCARINA << 8 | 6, sNotePlaybackVibrato);
// Update bend
if (sNotePlaybackBend != sPlaybackSong[sPlaybackNotePos].bend) {
@@ -2746,14 +2748,14 @@ void AudioOcarina_PlaybackSong(void) {
sPlaybackStaffPos++;
// Sets ocarina instrument Id to io port 7, which is used
// as an index in seq 0 to get the true instrument Id
Audio_QueueCmdS8(0x6 << 24 | SEQ_PLAYER_SFX << 16 | SFX_CHANNEL_OCARINA << 8 | 7,
sOcarinaInstrumentId - 1);
Audio_QueueCmdS8(0x6 << 24 | SEQ_PLAYER_SFX << 16 | SFX_CHANNEL_OCARINA << 8 | 5,
sPlaybackPitch & OCARINA_BUTTON_MASK_PITCH);
Audio_PlaySfxGeneral(NA_SE_OC_OCARINA, &gSfxDefaultPos, 4, &sRelativeNotePlaybackBend,
&sRelativeNotePlaybackVolume, &gSfxDefaultReverb);
AudioThread_QueueCmdS8(0x6 << 24 | SEQ_PLAYER_SFX << 16 | SFX_CHANNEL_OCARINA << 8 | 7,
sOcarinaInstrumentId - 1);
AudioThread_QueueCmdS8(0x6 << 24 | SEQ_PLAYER_SFX << 16 | SFX_CHANNEL_OCARINA << 8 | 5,
sPlaybackPitch & OCARINA_BUTTON_MASK_PITCH);
AudioSfx_PlaySfx(NA_SE_OC_OCARINA, &gSfxDefaultPos, 4, &sRelativeNotePlaybackBend,
&sRelativeNotePlaybackVolume, &gSfxDefaultReverb);
} else {
Audio_StopSfxById(NA_SE_OC_OCARINA);
AudioSfx_StopById(NA_SE_OC_OCARINA);
}
}
sPlaybackNotePos++;
@@ -3073,7 +3075,7 @@ void AudioOcarina_TerminaWallGenerateNotes(void) {
j = 0;
for (; i < 8; i++) {
randomButtonIndex = Audio_NextRandom() % ARRAY_COUNT(sButtonToPitchMap);
randomButtonIndex = AudioThread_NextRandom() % ARRAY_COUNT(sButtonToPitchMap);
sOcarinaSongNotes[OCARINA_SONG_TERMINA_WALL][j].pitch = sButtonToPitchMap[randomButtonIndex];
sOcarinaSongNotes[OCARINA_SONG_TERMINA_WALL][j].length = 19;
sOcarinaSongNotes[OCARINA_SONG_TERMINA_WALL][j].volume = 80;
@@ -3094,7 +3096,7 @@ void AudioOcarina_TerminaWallGenerateNotes(void) {
sOcarinaSongNotes[OCARINA_SONG_TERMINA_WALL][j + 1].length = 0;
AudioOcarina_MapSongFromPitchToButton(OCARINA_SONG_TERMINA_WALL, OCARINA_SONG_TERMINA_WALL, 8);
} else {
j = Audio_NextRandom() % ARRAY_COUNT(sOoTOcarinaSongNotes);
j = AudioThread_NextRandom() % ARRAY_COUNT(sOoTOcarinaSongNotes);
ocarinaNote = sOoTOcarinaSongNotes[j];
for (; ocarinaNote[i].length != 0; i++) {
@@ -3140,7 +3142,7 @@ s32 AudioOcarina_MemoryGameNextNote(void) {
return true;
}
randomButtonIndex = Audio_NextRandom();
randomButtonIndex = AudioThread_NextRandom();
randomPitch = sButtonToPitchMap[randomButtonIndex % ARRAY_COUNT(sButtonToPitchMap)];
if (sOcarinaSongNotes[OCARINA_SONG_MEMORY_GAME][sOcarinaMemoryGameAppendPos - 1].pitch == randomPitch) {
@@ -3234,7 +3236,7 @@ void AudioOcarina_PlayLongScarecrowAfterCredits(void) {
break;
case 1:
Audio_SetSfxBanksMute(0);
AudioSfx_MuteBanks(0);
AudioOcarina_SetInstrument(sScarecrowAfterCreditsIntrumentId);
AudioOcarina_SetPlaybackSong(OCARINA_SONG_SCARECROW_LONG + 1, 1);
sScarecrowAfterCreditsIntrumentId++;
@@ -3475,20 +3477,6 @@ void AudioOcarina_ResetStaffs(void) {
D_801D8534 = 0;
}
s8 D_801D8B30[] = {
0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55,
56, 56, 57, 57, 58, 58, 59, 59, 60, 60, 60, 61, 61, 61, 62, 62, 62, 63, 63, 63, 64, 64,
64, 65, 65, 65, 66, 66, 66, 67, 67, 67, 68, 68, 69, 69, 70, 70, 71, 71, 72, 73, 74, 75,
76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97,
98, 99, 100, 101, 102, 103, 105, 107, 109, 111, 113, 115, 117, 119, 121, 123, 125, 127,
};
f32 sBigBellsVolume[8] = {
1.0f, 0.9f, 0.8f, 0.7f, 0.6f, 0.5f, 0.4f, 0.3f,
};
u8 sBgmPlayers[2] = { SEQ_PLAYER_BGM_MAIN, SEQ_PLAYER_BGM_SUB };
f32 sSfxOriginalPos[] = { 0.0f, 0.0f, 0.0f };
#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_8019DFF8.s")
#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_8019E000.s")
@@ -3503,23 +3491,447 @@ f32 sSfxOriginalPos[] = { 0.0f, 0.0f, 0.0f };
#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_8019E110.s")
#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_8019E14C.s")
f32 AudioSfx_ComputeVolume(u8 bankId, u8 entryIndex) {
SfxBankEntry* bankEntry = &gSfxBanks[bankId][entryIndex];
f32 minDist;
f32 phi_f14;
f32 baseDist;
f32 phi_f12;
f32 volume; // Also acts as intermediate volumeSquared
s32 pad[3];
#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_8019E324.s")
if (bankEntry->sfxParams & SFX_FLAG_VOLUME_NO_DIST) {
return 1.0f;
}
#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_8019E4B0.s")
if (bankEntry->dist > 10000.0f) {
volume = 0.0f;
} else {
if (bankEntry->sfxParams & SFX_PARAM_DIST_RANGE_MASK_UPPER) {
phi_f12 = 0.35f;
phi_f14 = 0.65f;
} else {
phi_f12 = 0.81f;
phi_f14 = 0.19f;
}
#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_8019E634.s")
switch (bankEntry->sfxParams & SFX_PARAM_DIST_RANGE_MASK) {
case 0:
baseDist = 500.0f;
break;
#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_8019E864.s")
case 1:
baseDist = 666.6667f;
break;
#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_8019EA40.s")
case 2:
baseDist = 952.381f;
break;
#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_8019EB2C.s")
case 3:
baseDist = 3846.154f;
break;
#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_8019F024.s")
case 4:
baseDist = 1000.0f;
break;
#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_8019F05C.s")
case 5:
baseDist = 666.6667f;
break;
case 6:
baseDist = 500.0f;
break;
case 7:
baseDist = 400.0f;
break;
}
minDist = baseDist / 5.0f;
if (bankEntry->dist < minDist) {
volume = 1.0f;
} else if (bankEntry->dist < baseDist) {
volume =
((((baseDist - minDist) - (bankEntry->dist - minDist)) / (baseDist - minDist)) * phi_f14) + phi_f12;
} else {
volume = (1.0f - ((bankEntry->dist - baseDist) / (10000.0f - baseDist))) * phi_f12;
}
volume = SQ(volume);
}
return volume;
}
s8 AudioSfx_ComputeReverb(u8 bankId, u8 entryIndex, u8 channelIndex) {
s8 distAdd = 0;
s32 scriptAdd = 0;
SfxBankEntry* entry = &gSfxBanks[bankId][entryIndex];
s32 reverb;
if (!(entry->sfxParams & SFX_FLAG_REVERB_NO_DIST)) {
if (entry->dist < 2500.0f) {
distAdd = *entry->posZ > 0.0f ? (entry->dist / 2500.0f) * 70.0f : (entry->dist / 2500.0f) * 91.0f;
} else {
distAdd = 70;
}
}
if (IS_SEQUENCE_CHANNEL_VALID(gAudioContext.seqPlayers[SEQ_PLAYER_SFX].channels[channelIndex])) {
scriptAdd = gAudioContext.seqPlayers[SEQ_PLAYER_SFX].channels[channelIndex]->soundScriptIO[1];
if (gAudioContext.seqPlayers[SEQ_PLAYER_SFX].channels[channelIndex]->soundScriptIO[1] < 0) {
scriptAdd = 0;
}
}
reverb = (*entry->reverbAdd & 0x7F) + distAdd;
if (entry->state != SFX_STATE_READY) {
reverb += scriptAdd;
}
if ((bankId != BANK_OCARINA) || (SFX_INDEX(entry->sfxId) >= 2)) {
reverb += sAudioEnvReverb + (sAudioCodeReverb & 0x3F) + sSpecReverb;
}
if (reverb > 0x7F) {
reverb = 0x7F;
}
return reverb;
}
s8 AudioSfx_ComputePanSigned(f32 x, f32 z, u8 token) {
f32 absX = ABS_ALT(x);
f32 absZ = ABS_ALT(z);
f32 pan;
if (absX > 8000.0f) {
absX = 8000.0f;
}
if (absZ > 8000.0f) {
absZ = 8000.0f;
}
if ((x == 0.0f) && (z == 0.0f)) {
pan = 0.5f;
} else if (absZ <= absX) {
pan = (16000.0f - absX) / (4.5f * (16000.0f - absZ));
if (x >= 0.0f) {
pan = 1.0f - pan;
}
} else {
pan = (x / (3.6f * absZ)) + 0.5f;
}
if ((absZ < 50.0f) && (absX < 50.0f)) {
pan = ((pan - 0.5f) * SQ(absX / 50.0f)) + 0.5f;
}
return (pan * 127.0f) + 0.5f;
}
f32 AudioSfx_ComputeFreqScale(u8 bankId, u8 entryIndex) {
s32 applyRandScaling = false;
SfxBankEntry* entry = &gSfxBanks[bankId][entryIndex];
f32 dist;
f32 freq = 1.0f;
if (entry->sfxParams & SFX_PARAM_RAND_FREQ_LOWER) {
freq = 1.0f - ((gAudioContext.audioRandom & 0xF) / 192.0f);
}
switch (bankId) {
case BANK_VOICE:
if (((entry->sfxId & 0xFF) < 0x40) && (sAudioBaseFilter2 != 0)) {
applyRandScaling = true;
} else if (((entry->sfxId & 0xFF) >= 0x40) && (sAudioExtraFilter2 != 0)) {
applyRandScaling = true;
}
break;
case BANK_PLAYER:
case BANK_ITEM:
if (sAudioBaseFilter2 != 0) {
applyRandScaling = true;
}
break;
case BANK_ENV:
case BANK_ENEMY:
if (((*entry->reverbAdd & 0x80) != 0) | (sAudioExtraFilter2 != 0)) {
applyRandScaling = true;
}
break;
case BANK_SYSTEM:
case BANK_OCARINA:
break;
default:
break;
}
if ((applyRandScaling == true) && !(entry->sfxParams & SFX_PARAM_RAND_FREQ_SCALE)) {
freq *= 1.0293 - ((gAudioContext.audioRandom & 0xF) / 144.0f);
}
dist = entry->dist;
if (!(entry->sfxParams & SFX_FLAG_VOLUME_NO_DIST) && !(entry->sfxParams & SFX_FLAG_FREQ_NO_DIST)) {
if (dist >= 10000.0f) {
freq += 0.2f;
} else {
freq += (0.2f * (dist / 10000.0f));
}
}
if ((entry->sfxParams & SFX_PARAM_RAND_FREQ_RAISE_MASK) != (0 << SFX_PARAM_RAND_FREQ_RAISE_SHIFT)) {
freq += (entry->randFreq / 192.0f);
}
return freq;
}
u8 AudioSfx_ComputeSurroundSoundFilter(f32 behindScreenZ, SfxBankEntry* entry, s8 panSigned) {
u8 lowPassCutoff;
u8 highPassCutoff;
u16* sfxParams;
f32 distParam;
f32 dist;
// Remnant of OoT
if (*entry->posZ < behindScreenZ) {
lowPassCutoff = 0;
} else {
lowPassCutoff = 0;
}
sfxParams = &entry->sfxParams;
if (*sfxParams & SFX_FLAG_SURROUND_LOWPASS_FILTER) {
lowPassCutoff = 0xF;
}
switch ((*sfxParams & SFX_PARAM_DIST_RANGE_MASK)) {
case 0:
distParam = 15.0f;
break;
case 1:
distParam = 12.0f;
break;
case 2:
distParam = 9.0f;
break;
case 3:
distParam = 6.0f;
break;
case 4:
distParam = 18.0f;
break;
case 5:
distParam = 21.0f;
break;
case 6:
distParam = 24.0f;
break;
case 7:
distParam = 27.0f;
break;
default:
break;
}
if (!(entry->sfxFlags & SFX_FLAG2_SURROUND_NO_HIGHPASS_FILTER)) {
if (entry->dist > 1923.077f) {
dist = 1923.077f;
} else {
dist = entry->dist;
}
highPassCutoff = (distParam * dist) / (2 * 1923.077f);
} else {
highPassCutoff = 0;
}
return (lowPassCutoff << 4) + highPassCutoff;
}
s8 AudioSfx_ComputeCombFilter(f32 posY, u16 sfxParams) {
s8 combFilterGain;
if (posY < 0.0f) {
if (posY < -625.0f) {
combFilterGain = -32;
} else {
combFilterGain = (s8)(((625.0f + posY) / 625.0f) * 31.0f) + 0xE0;
}
} else if (posY > 1250.0f) {
combFilterGain = 127;
} else {
combFilterGain = (posY / 1250.0f) * 126.0f;
}
return combFilterGain | 1;
}
void AudioSfx_SetProperties(u8 bankId, u8 entryIndex, u8 channelIndex) {
static s8 sZVolumes[] = {
0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55,
56, 56, 57, 57, 58, 58, 59, 59, 60, 60, 60, 61, 61, 61, 62, 62, 62, 63, 63, 63, 64, 64,
64, 65, 65, 65, 66, 66, 66, 67, 67, 67, 68, 68, 69, 69, 70, 70, 71, 71, 72, 73, 74, 75,
76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97,
98, 99, 100, 101, 102, 103, 105, 107, 109, 111, 113, 115, 117, 119, 121, 123, 125, 127,
};
f32 volume = 1.0f;
s8 volumeS8;
s8 reverb = 0;
f32 freqScale = 1.0f;
s8 panSigned = 0x40;
u8 pad;
u8 filter = 0;
s8 combFilterGain = 0;
s8 zVolume = -1;
f32 behindScreenZ;
u8 baseFilter = 0;
SfxBankEntry* entry = &gSfxBanks[bankId][entryIndex];
s32 pad2;
switch (bankId) {
case BANK_PLAYER:
case BANK_ITEM:
case BANK_ENV:
case BANK_ENEMY:
case BANK_VOICE:
if (sSoundMode == SOUNDMODE_SURROUND) {
combFilterGain = AudioSfx_ComputeCombFilter(*entry->posY, entry->sfxParams);
}
// fallthrough
case BANK_OCARINA:
entry->dist = sqrtf(entry->dist * 10.0f);
volume = AudioSfx_ComputeVolume(bankId, entryIndex) * *entry->volume;
reverb = AudioSfx_ComputeReverb(bankId, entryIndex, channelIndex);
panSigned = AudioSfx_ComputePanSigned(*entry->posX, *entry->posZ, entry->token);
freqScale = AudioSfx_ComputeFreqScale(bankId, entryIndex) * *entry->freqScale;
if (sSoundMode == SOUNDMODE_SURROUND) {
if (*entry->posZ >= 0.0f) {
if (*entry->posZ < 200.0f) {
zVolume = 32.0f - ((*entry->posZ / 300.0f) * 32.0f);
} else {
zVolume = 0;
}
} else if (*entry->posZ < 0.0f) {
if (*entry->posZ > -300.0f) {
zVolume = 32.0f - ((*entry->posZ / 300.0f) * 95.0f);
} else {
zVolume = 127;
}
}
zVolume = sZVolumes[zVolume];
}
if (sAudioBaseFilter != 0) {
if ((bankId == BANK_PLAYER) || (bankId == BANK_ITEM) ||
((bankId == BANK_VOICE) && (((entry->sfxId & 0xFF) < 0x40) || ((entry->sfxId & 0xFF) >= 0x80)))) {
baseFilter = sAudioBaseFilter;
if (sAudioExtraFilter) {
reverb >>= 2;
}
}
}
if (((*entry->reverbAdd & 0x80) | baseFilter | sAudioExtraFilter |
(entry->sfxFlags & SFX_FLAG2_APPLY_LOWPASS_FILTER)) != 0) {
filter = ((((*entry->reverbAdd & 0x80) >> 2) | baseFilter | sAudioExtraFilter |
((entry->sfxFlags & SFX_FLAG2_APPLY_LOWPASS_FILTER) >> 2)) *
2);
filter &= 0xFF;
} else if ((sSoundMode == SOUNDMODE_SURROUND) && !(entry->sfxParams & SFX_FLAG_VOLUME_NO_DIST)) {
filter = AudioSfx_ComputeSurroundSoundFilter(behindScreenZ, entry, panSigned);
}
break;
case BANK_SYSTEM:
break;
}
if (sSfxChannelState[channelIndex].volume != volume) {
volumeS8 = (u8)(volume * 127.0f);
sSfxChannelState[channelIndex].volume = volume;
} else {
volumeS8 = -1;
}
//! FAKE:
if (1) {}
// CHAN_UPD_SCRIPT_IO (slot 2, sets volume)
AudioThread_QueueCmdS8((0x6 << 24) | (SEQ_PLAYER_SFX << 16) | (channelIndex << 8) | 2, volumeS8);
if (sSfxChannelState[channelIndex].reverb != reverb) {
sSfxChannelState[channelIndex].reverb = reverb;
}
if (sSfxChannelState[channelIndex].freqScale != freqScale) {
sSfxChannelState[channelIndex].freqScale = freqScale;
}
if (sSfxChannelState[channelIndex].stereoBits != 0) {
sSfxChannelState[channelIndex].stereoBits = 0;
}
if (sSfxChannelState[channelIndex].filter != filter) {
sSfxChannelState[channelIndex].filter = filter;
}
if (sSfxChannelState[channelIndex].combFilterGain != combFilterGain) {
sSfxChannelState[channelIndex].combFilterGain = combFilterGain;
}
if (sSfxChannelState[channelIndex].zVolume != zVolume) {
sSfxChannelState[channelIndex].zVolume = zVolume;
}
if (sSfxChannelState[channelIndex].panSigned != panSigned) {
sSfxChannelState[channelIndex].panSigned = panSigned;
}
}
u32 AudioSfx_SetFreqAndStereoBits(u8 seqScriptValIn, SequenceChannel* channel) {
channel->stereo.asByte = sSfxChannelState[seqScriptValIn].stereoBits;
channel->freqScale = sSfxChannelState[seqScriptValIn].freqScale;
channel->changes.s.freqScale = true;
return seqScriptValIn;
}
void AudioSfx_ResetSfxChannelState(void) {
SfxChannelState* state;
u8 i;
for (i = 0; i < ARRAY_COUNT(sSfxChannelState); i++) {
state = &sSfxChannelState[i];
state->volume = 1.0f;
state->freqScale = 1.0f;
state->reverb = 0;
state->panSigned = 0x40;
state->stereoBits = 0;
state->filter = 0xFF;
state->combFilterGain = 0xFF;
state->zVolume = 0xFF;
}
sSfxChannelState[SFX_CHANNEL_OCARINA].combFilterGain = 0;
sPrevSeqMode = SEQ_MODE_DEFAULT;
sAudioCodeReverb = 0;
}
#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/play_sound.s")
@@ -3533,9 +3945,75 @@ f32 sSfxOriginalPos[] = { 0.0f, 0.0f, 0.0f };
#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_8019F230.s")
#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_8019F258.s")
SfxSettings* AudioSfx_AddSfxSetting(Vec3f* pos) {
SfxSettings* sfxSettings;
u8 i = 0;
u8 sfxSettingIndex = 0xFF;
#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_8019F300.s")
for (; i < ARRAY_COUNT(sSfxSettings); i++) {
sfxSettings = &sSfxSettings[i];
if ((sfxSettings->pos == NULL) && (sfxSettingIndex == 0xFF)) {
sfxSettingIndex = i;
}
if (sfxSettings->pos == pos) {
return sfxSettings;
}
}
if (sfxSettingIndex != 0xFF) {
sSfxSettingsFlags |= 1 << sfxSettingIndex;
sfxSettings = &sSfxSettings[sfxSettingIndex];
sfxSettings->pos = pos;
return sfxSettings;
}
return NULL;
}
void AudioSfx_ProcessSfxSettings(void) {
SfxBankEntry* entry;
u8 sfxSettingsFlags;
u8 sfxSettingIndex = 0;
u8 bankId;
u8 entryIndex;
s32 found;
if (sSfxSettingsFlags != 0) {
sfxSettingsFlags = sSfxSettingsFlags;
while (sfxSettingsFlags != 0) {
bankId = BANK_ENV;
if ((sfxSettingsFlags & (1 << sfxSettingIndex))) {
found = false;
while ((bankId <= BANK_ENEMY) && !found) {
entryIndex = gSfxBanks[bankId]->next;
while (entryIndex != 0xFF) {
entry = &gSfxBanks[bankId][entryIndex];
entryIndex = 0xFF;
if (entry->posX == &sSfxSettings[sfxSettingIndex].pos->x) {
found = true;
} else {
entryIndex = entry->next;
}
}
bankId++;
}
if (!found) {
sSfxSettingsFlags ^= (1 << sfxSettingIndex);
sSfxSettings[sfxSettingIndex].pos = NULL;
}
sfxSettingsFlags ^= (1 << sfxSettingIndex);
}
sfxSettingIndex++;
}
}
}
#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_8019F420.s")
@@ -3543,7 +4021,17 @@ f32 sSfxOriginalPos[] = { 0.0f, 0.0f, 0.0f };
#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_8019F540.s")
#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_8019F570.s")
void AudioSfx_LowerSfxSettingsReverb(Vec3f* pos, s8 isReverbLowered) {
SfxSettings* sfxSettings = AudioSfx_AddSfxSetting(pos);
if (sfxSettings != NULL) {
if (isReverbLowered) {
sfxSettings->reverbAdd = -0x80;
} else {
sfxSettings->reverbAdd = 0;
}
}
}
#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_8019F5AC.s")
@@ -3585,15 +4073,15 @@ f32 sSfxOriginalPos[] = { 0.0f, 0.0f, 0.0f };
* Used for EnRiverSound
*/
void Audio_PlaySfxForRiver(Vec3f* pos, f32 freqScale) {
if (!Audio_IsSfxPlaying(NA_SE_EV_RIVER_STREAM - SFX_FLAG)) {
if (!AudioSfx_IsPlaying(NA_SE_EV_RIVER_STREAM - SFX_FLAG)) {
sRiverFreqScaleLerp.value = freqScale;
} else if (freqScale != sRiverFreqScaleLerp.value) {
sRiverFreqScaleLerp.target = freqScale;
sRiverFreqScaleLerp.remainingFrames = 40;
sRiverFreqScaleLerp.step = (sRiverFreqScaleLerp.target - sRiverFreqScaleLerp.value) / 40;
}
Audio_PlaySfxGeneral(NA_SE_EV_RIVER_STREAM - SFX_FLAG, pos, 4, &sRiverFreqScaleLerp.value, &D_801DB4B0,
&gSfxDefaultReverb);
AudioSfx_PlaySfx(NA_SE_EV_RIVER_STREAM - SFX_FLAG, pos, 4, &sRiverFreqScaleLerp.value, &gSfxDefaultFreqAndVolScale,
&gSfxDefaultReverb);
}
/**
@@ -3601,15 +4089,15 @@ void Audio_PlaySfxForRiver(Vec3f* pos, f32 freqScale) {
* Used for Zora's River Waterfall
*/
void Audio_PlaySfxForWaterfall(Vec3f* pos, f32 freqScale) {
if (!Audio_IsSfxPlaying(NA_SE_EV_WATER_WALL_BIG - SFX_FLAG)) {
if (!AudioSfx_IsPlaying(NA_SE_EV_WATER_WALL_BIG - SFX_FLAG)) {
sWaterfallFreqScaleLerp.value = freqScale;
} else if (freqScale != sWaterfallFreqScaleLerp.value) {
sWaterfallFreqScaleLerp.target = freqScale;
sWaterfallFreqScaleLerp.remainingFrames = 40;
sWaterfallFreqScaleLerp.step = (sWaterfallFreqScaleLerp.target - sWaterfallFreqScaleLerp.value) / 40;
}
Audio_PlaySfxGeneral(NA_SE_EV_WATER_WALL_BIG - SFX_FLAG, pos, 4, &sWaterfallFreqScaleLerp.value,
&sWaterfallFreqScaleLerp.value, &gSfxDefaultReverb);
AudioSfx_PlaySfx(NA_SE_EV_WATER_WALL_BIG - SFX_FLAG, pos, 4, &sWaterfallFreqScaleLerp.value,
&sWaterfallFreqScaleLerp.value, &gSfxDefaultReverb);
}
/**
@@ -3626,6 +4114,9 @@ void Audio_StepFreqLerp(FreqLerp* lerp) {
}
}
f32 sBigBellsVolume[8] = {
1.0f, 0.9f, 0.8f, 0.7f, 0.6f, 0.5f, 0.4f, 0.3f,
};
#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_801A0124.s")
#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_801A0184.s")
@@ -3652,7 +4143,7 @@ void Audio_SetGanonsTowerBgmVolumeLevel(u8 ganonsTowerLevel) {
for (channelIndex = 0; channelIndex < 16; channelIndex++) {
// CHAN_UPD_PAN_UNSIGNED
Audio_QueueCmdS8(((u8)(u32)channelIndex << 8) | 0x7000000, pan);
AudioThread_QueueCmdS8(((u8)(u32)channelIndex << 8) | 0x7000000, pan);
}
// Lowest room in Ganon's Tower (Entrance Room)
@@ -3710,9 +4201,9 @@ s32 Audio_SetGanonsTowerBgmVolume(u8 targetVolume) {
}
// CHAN_UPD_REVERB
Audio_QueueCmdS8(_SHIFTL(5, 24, 8) | _SHIFTL(SEQ_PLAYER_BGM_MAIN, 16, 8) |
_SHIFTL(channelIndex, 8, 8),
(u8)reverb);
AudioThread_QueueCmdS8(_SHIFTL(5, 24, 8) | _SHIFTL(SEQ_PLAYER_BGM_MAIN, 16, 8) |
_SHIFTL(channelIndex, 8, 8),
(u8)reverb);
}
}
}
@@ -3768,7 +4259,29 @@ void Audio_UpdateRiverSoundVolumes(void) {
#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_801A05F0.s")
#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_801A0654.s")
void AudioSfx_SetChannelIO(Vec3f* pos, u16 sfxId, u8 ioData) {
u8 channelIndex = 0;
u8 bankId = SFX_BANK_SHIFT(sfxId);
u8 entryIndex;
u8 i;
for (i = 0; i < bankId; i++) {
channelIndex += gChannelsPerBank[gSfxChannelLayout][i];
}
for (i = 0; i < gChannelsPerBank[gSfxChannelLayout][bankId]; i++) {
entryIndex = gActiveSfx[bankId][i].entryIndex;
if (entryIndex != 0xFF) {
if ((sfxId == gSfxBanks[bankId][entryIndex].sfxId) && (&pos->x == gSfxBanks[bankId][entryIndex].posX)) {
AudioThread_QueueCmdS8(_SHIFTL(6, 24, 8) | _SHIFTL(SEQ_PLAYER_SFX, 16, 8) |
_SHIFTL(channelIndex, 8, 8) | _SHIFTL(6, 0, 8),
ioData);
}
}
channelIndex++;
}
}
#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_801A0810.s")
@@ -3814,7 +4327,7 @@ void func_801A09D4(Vec3f* pos, f32 xzDistToPlayer) {
if (channelIndex != 9) {
Audio_QueueSeqCmd(((u32)(6) << 28) | ((u32)(SEQ_PLAYER_BGM_MAIN) << 24) | ((u32)(2) << 16) |
((u32)(channelIndex) << 8) | ((u8)(127.0f * volumeRel)));
Audio_QueueCmdS8(0x03000000 | ((u8)((u32)channelIndex) << 8), pan);
AudioThread_QueueCmdS8(0x03000000 | ((u8)((u32)channelIndex) << 8), pan);
}
}
}
@@ -3837,6 +4350,7 @@ void Audio_ClearSariaBgmAtPos(Vec3f* pos) {
}
}
u8 sBgmPlayers[2] = { SEQ_PLAYER_BGM_MAIN, SEQ_PLAYER_BGM_SUB };
void Audio_SplitBgmChannels(s8 volumeSplit);
#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/Audio_SplitBgmChannels.s")
@@ -4043,6 +4557,7 @@ void Audio_ClearSariaBgm2(void) {
#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_801A46F8.s")
f32 sSfxOriginalPos[] = { 0.0f, 0.0f, 0.0f };
#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_801A4748.s")
#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_801A479C.s")
@@ -4053,11 +4568,27 @@ void Audio_ClearSariaBgm2(void) {
#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_801A4A28.s")
#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_801A4B80.s")
u32 Audio_SetNatureAmbienceRandomBend(u8 seqScriptValIn, SequenceChannel* channel);
#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/Audio_SetNatureAmbienceRandomBend.s")
#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_801A4C30.s")
void Audio_Init(void) {
AudioLoad_Init(NULL, 0);
}
#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_801A4C54.s")
void AudioSfx_Init(u16 fadeTimer) {
u8 channelIndex;
AudioThread_ScheduleProcessCmds();
Audio_StartSequence(SEQ_PLAYER_SFX, NA_BGM_GENERAL_SFX, 0x70, fadeTimer);
for (channelIndex = 0; channelIndex < ARRAY_COUNT(sSfxChannelState); channelIndex++) {
AudioThread_QueueCmdS32(0x10 << 24 | SEQ_PLAYER_SFX << 16 | ((u8)(u32)channelIndex << 8),
&sSfxChannelState[channelIndex]);
}
AudioThread_QueueCmdS32(0xE4000000, AudioSfx_SetFreqAndStereoBits);
AudioThread_QueueCmdS32(0xE4000001, Audio_SetNatureAmbienceRandomBend);
}
#pragma GLOBAL_ASM("asm/non_matchings/code/code_8019AF00/func_801A4D00.s")
+928 -22
View File
@@ -1,45 +1,951 @@
#include "global.h"
#pragma GLOBAL_ASM("asm/non_matchings/code/code_801A5BD0/Audio_SetSfxBanksMute.s")
typedef struct {
/* 0x00 */ u16 sfxId;
/* 0x02 */ u8 token;
/* 0x04 */ s8* reverbAdd;
/* 0x08 */ Vec3f* pos;
/* 0x0C */ f32* freqScale;
/* 0x10 */ f32* volume;
} SfxRequest; // size = 0x14
#pragma GLOBAL_ASM("asm/non_matchings/code/code_801A5BD0/Audio_SetFlagForBgmVolumeLow.s")
typedef struct {
/* 0x0 */ f32 value;
/* 0x4 */ f32 target;
/* 0x8 */ f32 step;
/* 0xC */ u16 remainingFrames;
} SfxBankLerp; // size = 0x10
#pragma GLOBAL_ASM("asm/non_matchings/code/code_801A5BD0/Audio_ClearFlagForBgmVolumeLow.s")
typedef enum {
/* 0 */ SFX_RM_REQ_BY_BANK,
/* 1 */ SFX_RM_REQ_BY_POS_AND_BANK,
/* 2 */ SFX_RM_REQ_BY_POS,
/* 3 */ SFX_RM_REQ_BY_POS_AND_ID,
/* 4 */ SFX_RM_REQ_BY_TOKEN_AND_ID,
/* 5 */ SFX_RM_REQ_BY_ID
} SfxRemoveRequest;
#pragma GLOBAL_ASM("asm/non_matchings/code/code_801A5BD0/Audio_PlaySfxGeneral.s")
SfxBankEntry sSfxPlayerBank[9];
SfxBankEntry sSfxItemBank[12];
SfxBankEntry sSfxEnvironmentBank[32];
SfxBankEntry sSfxEnemyBank[20];
SfxBankEntry sSfxSystemBank[8];
SfxBankEntry sSfxOcarinaBank[3];
SfxBankEntry sSfxVoiceBank[5];
SfxRequest sSfxRequests[0x100];
u8 sSfxBankListEnd[7];
u8 sSfxBankFreeListStart[7];
u8 sSfxBankUnused[7];
ActiveSfx gActiveSfx[7][3];
u8 sCurSfxPlayerChannelIndex;
u8 gSfxBankMuted[7];
SfxBankLerp sSfxBankLerp[7];
#pragma GLOBAL_ASM("asm/non_matchings/code/code_801A5BD0/func_801A5DDC.s")
// sSfxRequests ring buffer endpoints. read index <= write index, wrapping around mod 256.
u8 sSfxRequestWriteIndex = 0;
u8 sSfxRequestReadIndex = 0;
#pragma GLOBAL_ASM("asm/non_matchings/code/code_801A5BD0/func_801A5F7C.s")
/**
* Array of pointers to arrays of SfxBankEntry of sizes: 9, 12, 32, 20, 8, 3, 5
*
* 0 : Player Bank size 9
* 1 : Item Bank size 12
* 2 : Environment Bank size 32
* 3 : Enemy Bank size 20
* 4 : System Bank size 8
* 5 : Ocarina Bank size 3
* 6 : Voice Bank size 5
*/
SfxBankEntry* gSfxBanks[7] = {
sSfxPlayerBank, sSfxItemBank, sSfxEnvironmentBank, sSfxEnemyBank, sSfxSystemBank, sSfxOcarinaBank, sSfxVoiceBank,
};
#pragma GLOBAL_ASM("asm/non_matchings/code/code_801A5BD0/func_801A6430.s")
u8 sSfxBankSizes[ARRAY_COUNT(gSfxBanks)] = {
ARRAY_COUNT(sSfxPlayerBank), ARRAY_COUNT(sSfxItemBank), ARRAY_COUNT(sSfxEnvironmentBank),
ARRAY_COUNT(sSfxEnemyBank), ARRAY_COUNT(sSfxSystemBank), ARRAY_COUNT(sSfxOcarinaBank),
ARRAY_COUNT(sSfxVoiceBank),
};
#pragma GLOBAL_ASM("asm/non_matchings/code/code_801A5BD0/func_801A65C8.s")
u8 gSfxChannelLayout = 0;
u16 sSfxChannelLowVolumeFlag = 0;
#pragma GLOBAL_ASM("asm/non_matchings/code/code_801A5BD0/func_801A6D0C.s")
// The center of the screen in projected coordinates.
// Gives the impression that the sfx has no specific location
Vec3f gSfxDefaultPos = { 0.0f, 0.0f, 0.0f };
#pragma GLOBAL_ASM("asm/non_matchings/code/code_801A5BD0/func_801A7084.s")
// Reused as either frequency or volume multiplicative scaling factor
// Does not alter or change frequency or volume
f32 gSfxDefaultFreqAndVolScale = 1.0f;
s32 D_801DB4B4 = 0; // unused
#pragma GLOBAL_ASM("asm/non_matchings/code/code_801A5BD0/func_801A7168.s")
// Adds no reverb to the existing reverb
s8 gSfxDefaultReverb = 0;
#pragma GLOBAL_ASM("asm/non_matchings/code/code_801A5BD0/func_801A7284.s")
void AudioSfx_MuteBanks(u16 muteMask) {
u8 bankId;
#pragma GLOBAL_ASM("asm/non_matchings/code/code_801A5BD0/Audio_StopSfxByPos.s")
for (bankId = 0; bankId < ARRAY_COUNT(gSfxBanks); bankId++) {
if (muteMask & 1) {
gSfxBankMuted[bankId] = true;
} else {
gSfxBankMuted[bankId] = false;
}
muteMask = muteMask >> 1;
}
}
#pragma GLOBAL_ASM("asm/non_matchings/code/code_801A5BD0/func_801A7328.s")
/**
* Lowers volumes of both bgm players so that sfx can be more pronounced.
* Each sfx channel stores its own bit to lower the volume.
* Only a single channel needs to request this to lower the volume.
*/
void AudioSfx_LowerBgmVolume(u8 channelIndex) {
sSfxChannelLowVolumeFlag |= (1 << channelIndex);
#pragma GLOBAL_ASM("asm/non_matchings/code/code_801A5BD0/func_801A7484.s")
Audio_SetVolumeScale(SEQ_PLAYER_BGM_MAIN, 2, 0x40, 0xF);
Audio_SetVolumeScale(SEQ_PLAYER_BGM_SUB, 2, 0x40, 0xF);
}
#pragma GLOBAL_ASM("asm/non_matchings/code/code_801A5BD0/Audio_StopSfxById.s")
/**
* Clears the flag for the specific channel to lower volume.
* If all flags are cleared, then both bgm players return to full volume
*/
void AudioSfx_RestoreBgmVolume(u8 channelIndex) {
sSfxChannelLowVolumeFlag &= ((1 << channelIndex) ^ 0xFFFF);
#pragma GLOBAL_ASM("asm/non_matchings/code/code_801A5BD0/func_801A7720.s")
if (sSfxChannelLowVolumeFlag == 0) {
Audio_SetVolumeScale(SEQ_PLAYER_BGM_MAIN, 2, 0x7F, 0xF);
Audio_SetVolumeScale(SEQ_PLAYER_BGM_SUB, 2, 0x7F, 0xF);
}
}
#pragma GLOBAL_ASM("asm/non_matchings/code/code_801A5BD0/func_801A7794.s")
/**
* The main function to request a sfx. All sfx requests begin here.
*/
void AudioSfx_PlaySfx(u16 sfxId, Vec3f* pos, u8 token, f32* freqScale, f32* volume, s8* reverbAdd) {
u8 i;
SfxRequest* reqWrite;
SfxRequest* reqRead;
#pragma GLOBAL_ASM("asm/non_matchings/code/code_801A5BD0/func_801A7828.s")
if (!gSfxBankMuted[SFX_BANK_SHIFT(sfxId)]) {
reqWrite = &sSfxRequests[sSfxRequestWriteIndex];
#pragma GLOBAL_ASM("asm/non_matchings/code/code_801A5BD0/func_801A787C.s")
for (i = sSfxRequestReadIndex; sSfxRequestWriteIndex != i; i++) {
reqRead = &sSfxRequests[i];
if ((reqRead->pos == pos) && (reqRead->sfxId == sfxId)) {
return;
}
}
#pragma GLOBAL_ASM("asm/non_matchings/code/code_801A5BD0/Audio_IsSfxPlaying.s")
reqWrite->sfxId = sfxId;
reqWrite->pos = pos;
reqWrite->token = token;
reqWrite->freqScale = freqScale;
reqWrite->volume = volume;
reqWrite->reverbAdd = reverbAdd;
sSfxRequestWriteIndex++;
}
}
#pragma GLOBAL_ASM("asm/non_matchings/code/code_801A5BD0/func_801A794C.s")
void AudioSfx_RemoveMatchingRequests(u8 aspect, SfxBankEntry* entry) {
SfxRequest* req;
s32 remove;
u8 i = sSfxRequestReadIndex;
for (; i != sSfxRequestWriteIndex; i++) {
remove = false;
req = &sSfxRequests[i];
switch (aspect) {
case SFX_RM_REQ_BY_BANK:
if (SFX_BANK_MASK(req->sfxId) == SFX_BANK_MASK(entry->sfxId)) {
remove = true;
}
break;
case SFX_RM_REQ_BY_POS_AND_BANK:
if ((SFX_BANK_MASK(req->sfxId) == SFX_BANK_MASK(entry->sfxId)) && (&req->pos->x == entry->posX)) {
remove = true;
}
break;
case SFX_RM_REQ_BY_POS:
if (&req->pos->x == entry->posX) {
remove = true;
}
break;
case SFX_RM_REQ_BY_POS_AND_ID:
if ((&req->pos->x == entry->posX) && (req->sfxId == entry->sfxId)) {
remove = true;
}
break;
case SFX_RM_REQ_BY_TOKEN_AND_ID:
if ((req->token == entry->token) && (req->sfxId == entry->sfxId)) {
remove = true;
}
break;
case SFX_RM_REQ_BY_ID:
if (req->sfxId == entry->sfxId) {
remove = true;
}
break;
default:
break;
}
if (remove) {
req->sfxId = 0;
}
}
}
void AudioSfx_ProcessRequest(void) {
u16 sfxId;
u8 channelCount;
u8 index;
SfxRequest* req = &sSfxRequests[sSfxRequestReadIndex];
SfxBankEntry* entry;
SfxParams* sfxParams;
s32 bankId;
u8 evictImportance;
u8 evictIndex = 0x80;
if (req->sfxId == 0) {
return;
}
bankId = SFX_BANK(req->sfxId);
channelCount = 0;
index = gSfxBanks[bankId][0].next;
// Compare the sfx request to all sfx bank entries
while ((index != 0xFF) && (index != 0)) {
// If an existing sfx from the same source exists in the bank, then we should either:
// renew if it is the same sfx, check if any sfx channels are available for that bank,
// interrupt that sfx and replace it with the new sfx request, or drop the new sfx request.
if (gSfxBanks[bankId][index].posX == &req->pos->x) {
// If the new sfx has equal importance to the existing sfx,
// drop the request if the existing sfx has the "SFX_FLAG_BLOCK_EQUAL_IMPORTANCE" flag.
// Otherwise, keep processing the new sfx request
if ((gSfxParams[SFX_BANK_SHIFT(req->sfxId)][SFX_INDEX(req->sfxId)].params &
SFX_FLAG_BLOCK_EQUAL_IMPORTANCE) &&
(gSfxParams[SFX_BANK_SHIFT(req->sfxId)][SFX_INDEX(req->sfxId)].importance ==
gSfxBanks[bankId][index].sfxImportance)) {
// Drop the new request
return;
}
if (gSfxBanks[bankId][index].sfxId == req->sfxId) {
// The new sfx is the same as the existing sfx
// Set channelCount to max value to reprocess the sfx
channelCount = gUsedChannelsPerBank[gSfxChannelLayout][bankId];
} else {
// Determine which sfx to evict based on importance if there are no more channels available
if (channelCount == 0) {
// If this is the first sfx at the same source, than store the existing sfx info into evict temps
evictIndex = index;
sfxId = gSfxBanks[bankId][index].sfxId & 0xFFFF;
evictImportance = gSfxParams[SFX_BANK_SHIFT(sfxId)][SFX_INDEX(sfxId)].importance;
} else if (gSfxBanks[bankId][index].sfxImportance < evictImportance) {
// If a different existing sfx is at the same source, than update the evict temps if the next
// existing src has lower importance than the previous existing source
evictIndex = index;
sfxId = gSfxBanks[bankId][index].sfxId & 0xFFFF;
evictImportance = gSfxParams[SFX_BANK_SHIFT(sfxId)][SFX_INDEX(sfxId)].importance;
}
channelCount++;
// There are no channels available, evict the lowest importance
if (channelCount == gUsedChannelsPerBank[gSfxChannelLayout][bankId]) {
if (gSfxParams[SFX_BANK_SHIFT(req->sfxId)][SFX_INDEX(req->sfxId)].importance >= evictImportance) {
index = evictIndex;
} else {
index = 0;
}
}
}
// Process this sfx by refreshing or replacing and existing sfx
if (channelCount == gUsedChannelsPerBank[gSfxChannelLayout][bankId]) {
sfxParams = &gSfxParams[SFX_BANK_SHIFT(req->sfxId)][SFX_INDEX(req->sfxId)];
// Interrupt existing sfx and play the new sfx instead.
if ((req->sfxId & SFX_FLAG_MASK) || (sfxParams->flags & SFX_FLAG2_FORCE_RESET) ||
(index == evictIndex)) {
// Restore bgm if the sfx about to be replaced has the right flag
if ((gSfxBanks[bankId][index].sfxParams & SFX_FLAG_LOWER_VOLUME_BGM) &&
(gSfxBanks[bankId][index].state != SFX_STATE_QUEUED)) {
AudioSfx_RestoreBgmVolume(gSfxBanks[bankId][index].channelIndex);
}
gSfxBanks[bankId][index].token = req->token;
gSfxBanks[bankId][index].sfxId = req->sfxId;
gSfxBanks[bankId][index].state = SFX_STATE_QUEUED;
gSfxBanks[bankId][index].freshness = 2;
gSfxBanks[bankId][index].freqScale = req->freqScale;
gSfxBanks[bankId][index].volume = req->volume;
gSfxBanks[bankId][index].reverbAdd = req->reverbAdd;
gSfxBanks[bankId][index].sfxParams = sfxParams->params;
gSfxBanks[bankId][index].sfxFlags = sfxParams->flags;
gSfxBanks[bankId][index].sfxImportance = sfxParams->importance;
} else if (gSfxBanks[bankId][index].state == SFX_STATE_PLAYING_ONE_FRAME) {
// The new sfx is "one-frame" and equals the existing sfx,
// continue playing the "one-frame" sfx by setting "SFX_STATE_PLAYING".
// This will avoid triggering deletion and get "SFX_STATE_REFRESH"
// The state will be set back to "SFX_STATE_PLAYING_ONE_FRAME" at the end of the cycle
gSfxBanks[bankId][index].state = SFX_STATE_PLAYING;
}
// Terminate loop, function is finished (nothing more is processed)
index = 0;
}
}
if (index != 0) {
index = gSfxBanks[bankId][index].next;
}
}
if ((gSfxBanks[bankId][sSfxBankFreeListStart[bankId]].next != 0xFF) && (index != 0)) {
// Allocate from free list
index = sSfxBankFreeListStart[bankId];
entry = &gSfxBanks[bankId][index];
entry->posX = &req->pos->x;
entry->posY = &req->pos->y;
entry->posZ = &req->pos->z;
entry->token = req->token;
entry->freqScale = req->freqScale;
entry->volume = req->volume;
entry->reverbAdd = req->reverbAdd;
sfxParams = &gSfxParams[SFX_BANK_SHIFT(req->sfxId)][SFX_INDEX(req->sfxId)];
entry->sfxParams = sfxParams->params;
entry->sfxFlags = sfxParams->flags;
entry->sfxImportance = sfxParams->importance;
entry->sfxId = req->sfxId;
entry->state = SFX_STATE_QUEUED;
entry->freshness = 2;
entry->prev = sSfxBankListEnd[bankId];
gSfxBanks[bankId][sSfxBankListEnd[bankId]].next = sSfxBankFreeListStart[bankId];
sSfxBankListEnd[bankId] = sSfxBankFreeListStart[bankId];
sSfxBankFreeListStart[bankId] = gSfxBanks[bankId][sSfxBankFreeListStart[bankId]].next;
gSfxBanks[bankId][sSfxBankFreeListStart[bankId]].prev = 0xFF;
entry->next = 0xFF;
}
}
void AudioSfx_RemoveBankEntry(u8 bankId, u8 entryIndex) {
SfxBankEntry* entry = &gSfxBanks[bankId][entryIndex];
u8 i;
if (entry->sfxParams & SFX_FLAG_LOWER_VOLUME_BGM) {
AudioSfx_RestoreBgmVolume(entry->channelIndex);
}
if (entryIndex == sSfxBankListEnd[bankId]) {
sSfxBankListEnd[bankId] = entry->prev;
} else {
gSfxBanks[bankId][entry->next].prev = entry->prev;
}
gSfxBanks[bankId][entry->prev].next = entry->next;
entry->next = sSfxBankFreeListStart[bankId];
entry->prev = 0xFF;
gSfxBanks[bankId][sSfxBankFreeListStart[bankId]].prev = entryIndex;
sSfxBankFreeListStart[bankId] = entryIndex;
entry->state = SFX_STATE_EMPTY;
for (i = 0; i < gChannelsPerBank[gSfxChannelLayout][bankId]; i++) {
if (gActiveSfx[bankId][i].entryIndex == entryIndex) {
gActiveSfx[bankId][i].entryIndex = 0xFF;
i = gChannelsPerBank[gSfxChannelLayout][bankId];
}
}
}
void AudioSfx_ChooseActiveSfx(u8 bankId) {
u8 numChosenSfx = 0;
u8 numChannels;
u8 entryIndex;
u8 i;
u8 j;
u8 k;
u8 sfxImportance;
u8 needNewSfx;
u8 chosenEntryIndex;
s32 pad;
SfxBankEntry* entry;
ActiveSfx chosenSfx[MAX_CHANNELS_PER_BANK];
ActiveSfx* activeSfx;
f32 entryPosY;
f32 entryPosX;
for (i = 0; i < MAX_CHANNELS_PER_BANK; i++) {
chosenSfx[i].priority = 0x7FFFFFFF;
chosenSfx[i].entryIndex = 0xFF;
}
entryIndex = gSfxBanks[bankId][0].next;
k = 0;
// Delete stale sfx and prioritize remaining sfx into the gActiveSfx arrays
while (entryIndex != 0xFF) {
// Update the freshness for an "all-frame" sfx if it is still queued
if ((gSfxBanks[bankId][entryIndex].state == SFX_STATE_QUEUED) &&
(gSfxBanks[bankId][entryIndex].sfxId & SFX_FLAG_MASK)) {
gSfxBanks[bankId][entryIndex].freshness--;
// If a "one-frame" sfx is still in "SFX_STATE_PLAYING_ONE_FRAME", then remove the sfx
} else if (!(gSfxBanks[bankId][entryIndex].sfxId & SFX_FLAG_MASK) &&
(gSfxBanks[bankId][entryIndex].state == SFX_STATE_PLAYING_ONE_FRAME)) {
// CHAN_UPD_SCRIPT_IO (ioPort 0, force stop sfx in seq 0)
AudioThread_QueueCmdS8(
(0x6 << 24) | (SEQ_PLAYER_SFX << 16) | (gSfxBanks[bankId][entryIndex].channelIndex << 8), 0);
AudioSfx_RemoveBankEntry(bankId, entryIndex);
}
// If a "all-frame" sfx goes 2 frames in the "queued" state
// (because it is too low priority), then remove the sfx
if (gSfxBanks[bankId][entryIndex].freshness == 0) {
AudioSfx_RemoveBankEntry(bankId, entryIndex);
} else if (gSfxBanks[bankId][entryIndex].state != SFX_STATE_EMPTY) {
// process the entry
entry = &gSfxBanks[bankId][entryIndex];
// Recompute distSq each frame since the sound's position may have changed
// (later converted into dist)
if (&gSfxDefaultPos.x == entry[0].posX) {
entry->dist = 0.0f;
} else {
entryPosY = *entry->posY * 1;
entryPosX = *entry->posX * 0.5f;
entry->dist = (SQ(entryPosX) + SQ(entryPosY) + SQ(*entry->posZ)) / 10.0f;
}
// Recompute priority, possibly based on sfx position relative to the camera.
// (Note that the priority is the opposite of importance; lower is more preserved)
sfxImportance = entry->sfxImportance;
if (entry->sfxParams & SFX_FLAG_PRIORITY_NO_DIST) {
// Priority is independent of distance
entry->priority = SQ(0xFF - sfxImportance) * SQ(76);
} else {
// Priority value increases with distance (more likely to eject)
if (entry->dist > 0x7FFFFFD0) {
// max distance
entry->dist = 0x70000008;
}
entry->priority = (u32)entry->dist + (SQ(0xFF - sfxImportance) * SQ(76));
if (*entry->posZ < 0.0f) {
entry->priority += (s32)(-*entry->posZ * 6.0f);
}
}
// Sfx is too far away, do not consider for chosen sfx
if (entry->dist > SQ(1e5f)) {
// If too far away and also playing, stop playing
if (entry->state == SFX_STATE_PLAYING) {
// CHAN_UPD_SCRIPT_IO (ioPort 0, force stop sfx in seq 0)
AudioThread_QueueCmdS8((0x6 << 24) | (SEQ_PLAYER_SFX << 16) | (entry->channelIndex << 8), 0);
if (entry->sfxId & SFX_FLAG_MASK) {
AudioSfx_RemoveBankEntry(bankId, entryIndex);
entryIndex = k;
}
}
} else {
// Loop through all channels allocated to a specific bank
// Choose which sfx from gSfxBanks to play
// This includes all sfx requests and sfx already playing
// Sort all current sfx entries in gSfxBanks by priority
// This is where the "active" sfx are chosen
numChannels = gChannelsPerBank[gSfxChannelLayout][bankId];
for (i = 0; i < numChannels; i++) {
// Sort all sfx entries by priority
if (chosenSfx[i].priority >= entry->priority) {
// Update the number of sfx to attampt to play
if (numChosenSfx < gChannelsPerBank[gSfxChannelLayout][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; // make this the last pass through the loop, here equivalent to "break"
}
}
}
k = entryIndex;
}
entryIndex = gSfxBanks[bankId][k].next;
}
// If a sfx is chosen, update its state
for (i = 0; i < numChosenSfx; i++) {
entry = &gSfxBanks[bankId][chosenSfx[i].entryIndex];
if (entry->state == SFX_STATE_QUEUED) {
// sfx is a new entry
entry->state = SFX_STATE_READY;
} else if (entry->state == SFX_STATE_PLAYING) {
// sfx is already playing
entry->state = SFX_STATE_PLAYING_REFRESH;
}
}
// Apply the chosenSfx to the activeSfx in each channel
numChannels = gChannelsPerBank[gSfxChannelLayout][bankId];
for (i = 0; i < numChannels; i++) {
needNewSfx = false;
activeSfx = &gActiveSfx[bankId][i];
// Check if a sfx is already in the channel
if (activeSfx->entryIndex == 0xFF) {
// No sfx playing in the channel
// Available for use
needNewSfx = true;
} else {
// The channel is already playing a sfx
// Get the entry of the sfx playing
entry = &gSfxBanks[bankId][activeSfx[0].entryIndex];
// Check the state of the sfx playing
if (entry->state == SFX_STATE_PLAYING) {
if (entry->sfxId & SFX_FLAG_MASK) {
// For "all-frames" sfx, remove the entry
AudioSfx_RemoveBankEntry(bankId, activeSfx->entryIndex);
} else {
// For "one-frame" sfx, reset the state to queued
entry->state = SFX_STATE_QUEUED;
entry->freshness = 0x80;
}
needNewSfx = true;
} else if (entry->state == SFX_STATE_EMPTY) {
// The sfx already in the channel is empty
// Can replace the sfx
activeSfx->entryIndex = 0xFF;
needNewSfx = true;
} else {
// Sfx is already playing as it should, nothing to do.
for (j = 0; j < numChannels; j++) {
if (activeSfx->entryIndex == chosenSfx[j].entryIndex) {
chosenSfx[j].entryIndex = 0xFF;
j = numChannels;
}
}
numChosenSfx--;
}
}
// enter the new sfx into the activeSfx
if (needNewSfx == true) {
for (j = 0; j < numChannels; j++) {
chosenEntryIndex = chosenSfx[j].entryIndex;
if ((chosenEntryIndex != 0xFF) &&
(gSfxBanks[bankId][chosenEntryIndex].state != SFX_STATE_PLAYING_REFRESH)) {
for (k = 0; k < numChannels; k++) {
if (chosenEntryIndex == gActiveSfx[bankId][k].entryIndex) {
needNewSfx = false;
k = numChannels; // "break; i.e. force for-loop to end"
}
}
if (needNewSfx == true) {
activeSfx->entryIndex = chosenEntryIndex;
chosenSfx[j].entryIndex = 0xFF;
j = numChannels + 1;
numChosenSfx--;
}
}
}
if (j == numChannels) {
// nothing found
activeSfx->entryIndex = 0xFF;
}
}
}
}
void AudioSfx_PlayActiveSfx(u8 bankId) {
u8 entryIndex;
SequenceChannel* channel;
SfxBankEntry* entry;
u8 i;
u8 ioPort5Data;
for (i = 0; i < gChannelsPerBank[gSfxChannelLayout][bankId]; i++) {
entryIndex = gActiveSfx[bankId][i].entryIndex;
// If entry is not empty
if (entryIndex != 0xFF) {
entry = &gSfxBanks[bankId][entryIndex];
channel = gAudioContext.seqPlayers[SEQ_PLAYER_SFX].channels[sCurSfxPlayerChannelIndex];
if (entry->state == SFX_STATE_READY) {
// Initialize a sfx (new sfx request)
entry->channelIndex = sCurSfxPlayerChannelIndex;
if (entry->sfxParams & SFX_FLAG_LOWER_VOLUME_BGM) {
AudioSfx_LowerBgmVolume(sCurSfxPlayerChannelIndex);
}
// Add noise that will offset the frequency of the sfx
if ((entry->sfxParams & SFX_PARAM_RAND_FREQ_RAISE_MASK) != (0 << SFX_PARAM_RAND_FREQ_RAISE_SHIFT)) {
switch (entry->sfxParams & SFX_PARAM_RAND_FREQ_RAISE_MASK) {
case (1 << SFX_PARAM_RAND_FREQ_RAISE_SHIFT):
entry->randFreq = AudioThread_NextRandom() & 0xF;
break;
case (2 << SFX_PARAM_RAND_FREQ_RAISE_SHIFT):
entry->randFreq = AudioThread_NextRandom() & 0x1F;
break;
case (3 << SFX_PARAM_RAND_FREQ_RAISE_SHIFT):
entry->randFreq = AudioThread_NextRandom() & 0x3F;
break;
default:
entry->randFreq = 0;
break;
}
}
// Calculate all the properties of sfx
AudioSfx_SetProperties(bankId, entryIndex, sCurSfxPlayerChannelIndex);
// CHAN_UPD_SCRIPT_IO (ioPort 0, enable the sfx to play in seq 0)
AudioThread_QueueCmdS8((0x6 << 24) | (SEQ_PLAYER_SFX << 16) | ((sCurSfxPlayerChannelIndex & 0xFF) << 8),
1);
// CHAN_UPD_SCRIPT_IO (ioPort 4, write the lower bits sfx index to seq 0 so it can find the right code
// to execute)
AudioThread_QueueCmdS8((0x6 << 24) | (SEQ_PLAYER_SFX << 16) |
((sCurSfxPlayerChannelIndex & 0xFF) << 8) | 4,
entry->sfxId & 0xFF);
// If the sfx bank has more than 255 entries (greater than a u8 can store),
// then store the Id in upper and lower bits
if (gIsLargeSfxBank[bankId]) {
// Store upper bits
ioPort5Data = ((u8)((entry->sfxId & 0x300) >> 7) + (u8)((entry->sfxId & 0xFF) >> 7));
} else {
ioPort5Data = 0;
}
if ((entry->sfxParams & SFX_FLAG_8) && (entry->freshness == 0x80)) {
ioPort5Data += 0x80;
}
if (D_801D6608[bankId]) {
// CHAN_UPD_SCRIPT_IO (ioPort 5, write the upper bits sfx index and a flag to seq 0, for banks with
// > 0xFF entries)
AudioThread_QueueCmdS8((0x6 << 24) | (SEQ_PLAYER_SFX << 16) |
((sCurSfxPlayerChannelIndex & 0xFF) << 8) | 5,
ioPort5Data);
}
// Update playing state
if (entry->sfxId & SFX_FLAG_MASK) {
// "all-frames" sfx
entry->state = SFX_STATE_PLAYING;
} else {
// "one-frame" sfx
entry->state = SFX_STATE_PLAYING_ONE_FRAME;
}
} else if ((u8)channel->soundScriptIO[1] == 0xFF) {
// Signal from seq 0 that the sfx is finished playing. Remove entry
AudioSfx_RemoveBankEntry(bankId, entryIndex);
} else if (entry->state == SFX_STATE_PLAYING_REFRESH) {
// Sfx is playing but a refresh is requested
AudioSfx_SetProperties(bankId, entryIndex, sCurSfxPlayerChannelIndex);
// Update playing state
if (entry->sfxId & SFX_FLAG_MASK) {
// "all-frames" sfx
entry->state = SFX_STATE_PLAYING;
} else {
// "one-frame" sfx
entry->state = SFX_STATE_PLAYING_ONE_FRAME;
}
}
}
sCurSfxPlayerChannelIndex++;
}
}
void AudioSfx_StopByBank(u8 bankId) {
SfxBankEntry* entry;
s32 pad;
SfxBankEntry entryToRemove;
u8 entryIndex = gSfxBanks[bankId][0].next;
while (entryIndex != 0xFF) {
entry = &gSfxBanks[bankId][entryIndex];
if (entry->state >= SFX_STATE_PLAYING_REFRESH) {
AudioThread_QueueCmdS8((0x6 << 24) | (SEQ_PLAYER_SFX << 16) | ((entry->channelIndex & 0xFF) << 8), 0);
}
if (entry->state != SFX_STATE_EMPTY) {
AudioSfx_RemoveBankEntry(bankId, entryIndex);
}
entryIndex = gSfxBanks[bankId][0].next;
}
entryToRemove.sfxId = bankId << 12;
AudioSfx_RemoveMatchingRequests(SFX_RM_REQ_BY_BANK, &entryToRemove);
}
void AudioSfx_StopByPosAndBankImpl(u8 bankId, Vec3f* pos) {
SfxBankEntry* entry;
u8 entryIndex = gSfxBanks[bankId][0].next;
u8 prevEntryIndex = 0;
while (entryIndex != 0xFF) {
entry = &gSfxBanks[bankId][entryIndex];
if (entry->posX == &pos->x) {
if (entry->state >= SFX_STATE_PLAYING_REFRESH) {
AudioThread_QueueCmdS8((0x6 << 24) | (SEQ_PLAYER_SFX << 16) | ((entry->channelIndex & 0xFF) << 8), 0);
}
if (entry->state != SFX_STATE_EMPTY) {
AudioSfx_RemoveBankEntry(bankId, entryIndex);
}
} else {
prevEntryIndex = entryIndex;
}
entryIndex = gSfxBanks[bankId][prevEntryIndex].next;
}
}
void AudioSfx_StopByPosAndBank(u8 bankId, Vec3f* pos) {
SfxBankEntry entryToRemove;
AudioSfx_StopByPosAndBankImpl(bankId, pos);
entryToRemove.sfxId = bankId << 12;
entryToRemove.posX = &pos->x;
AudioSfx_RemoveMatchingRequests(SFX_RM_REQ_BY_POS_AND_BANK, &entryToRemove);
}
void AudioSfx_StopByPos(Vec3f* pos) {
u8 bankId;
SfxBankEntry entryToRemove;
for (bankId = 0; bankId < ARRAY_COUNT(gSfxBanks); bankId++) {
AudioSfx_StopByPosAndBankImpl(bankId, pos);
}
entryToRemove.posX = &pos->x;
AudioSfx_RemoveMatchingRequests(SFX_RM_REQ_BY_POS, &entryToRemove);
}
void AudioSfx_StopByPosAndId(Vec3f* pos, u16 sfxId) {
SfxBankEntry* entry;
u8 entryIndex = gSfxBanks[SFX_BANK(sfxId)][0].next;
u8 prevEntryIndex = 0;
SfxBankEntry entryToRemove;
while (entryIndex != 0xFF) {
entry = &gSfxBanks[SFX_BANK(sfxId)][entryIndex];
if ((entry->posX == &pos->x) && (entry->sfxId == sfxId)) {
if (entry->state >= SFX_STATE_PLAYING_REFRESH) {
AudioThread_QueueCmdS8((0x6 << 24) | (SEQ_PLAYER_SFX << 16) | ((entry->channelIndex & 0xFF) << 8), 0);
}
if (entry->state != SFX_STATE_EMPTY) {
AudioSfx_RemoveBankEntry(SFX_BANK(sfxId), entryIndex);
}
entryIndex = 0xFF;
} else {
prevEntryIndex = entryIndex;
}
if (entryIndex != 0xFF) {
entryIndex = gSfxBanks[SFX_BANK(sfxId)][prevEntryIndex].next;
}
}
entryToRemove.posX = &pos->x;
entryToRemove.sfxId = sfxId;
AudioSfx_RemoveMatchingRequests(SFX_RM_REQ_BY_POS_AND_ID, &entryToRemove);
}
void AudioSfx_StopByTokenAndId(u8 token, u16 sfxId) {
SfxBankEntry* entry;
u8 entryIndex = gSfxBanks[SFX_BANK(sfxId)][0].next;
u8 prevEntryIndex = 0;
SfxBankEntry entryToRemove;
while (entryIndex != 0xFF) {
entry = &gSfxBanks[SFX_BANK(sfxId)][entryIndex];
if ((entry->token == token) && (entry->sfxId == sfxId)) {
if (entry->state >= SFX_STATE_PLAYING_REFRESH) {
AudioThread_QueueCmdS8((0x6 << 24) | (SEQ_PLAYER_SFX << 16) | ((entry->channelIndex & 0xFF) << 8), 0);
}
if (entry->state != SFX_STATE_EMPTY) {
AudioSfx_RemoveBankEntry(SFX_BANK(sfxId), entryIndex);
}
} else {
prevEntryIndex = entryIndex;
}
if (entryIndex != 0xFF) {
entryIndex = gSfxBanks[SFX_BANK(sfxId)][prevEntryIndex].next;
}
}
entryToRemove.token = token;
entryToRemove.sfxId = sfxId;
AudioSfx_RemoveMatchingRequests(SFX_RM_REQ_BY_TOKEN_AND_ID, &entryToRemove);
}
void AudioSfx_StopById(u32 sfxId) {
SfxBankEntry* entry;
u8 entryIndex = gSfxBanks[SFX_BANK(sfxId)][0].next;
u8 prevEntryIndex = 0;
SfxBankEntry entryToRemove;
while (entryIndex != 0xFF) {
entry = &gSfxBanks[SFX_BANK(sfxId)][entryIndex];
if (entry->sfxId == sfxId) {
if (entry->state >= SFX_STATE_PLAYING_REFRESH) {
AudioThread_QueueCmdS8((0x6 << 24) | (SEQ_PLAYER_SFX << 16) | ((entry->channelIndex & 0xFF) << 8), 0);
}
if (entry->state != SFX_STATE_EMPTY) {
AudioSfx_RemoveBankEntry(SFX_BANK(sfxId), entryIndex);
}
} else {
prevEntryIndex = entryIndex;
}
entryIndex = gSfxBanks[SFX_BANK(sfxId)][prevEntryIndex].next;
}
entryToRemove.sfxId = sfxId;
AudioSfx_RemoveMatchingRequests(SFX_RM_REQ_BY_ID, &entryToRemove);
}
void AudioSfx_ProcessRequests(void) {
if (gAudioContext.seqPlayers[SEQ_PLAYER_SFX].enabled) {
while (sSfxRequestWriteIndex != sSfxRequestReadIndex) {
AudioSfx_ProcessRequest();
sSfxRequestReadIndex++;
}
}
}
/**
* Unused
*/
void AudioSfx_SetBankLerp(u8 bankId, u8 target, u16 delay) {
if (delay == 0) {
delay++;
}
sSfxBankLerp[bankId].target = target / 127.0f;
sSfxBankLerp[bankId].remainingFrames = delay;
sSfxBankLerp[bankId].step = ((sSfxBankLerp[bankId].value - sSfxBankLerp[bankId].target) / delay);
}
/**
* Unused
*/
void AudioSfx_StepBankLerp(u8 bankId) {
if (sSfxBankLerp[bankId].remainingFrames != 0) {
sSfxBankLerp[bankId].remainingFrames--;
if (sSfxBankLerp[bankId].remainingFrames != 0) {
sSfxBankLerp[bankId].value -= sSfxBankLerp[bankId].step;
} else {
sSfxBankLerp[bankId].value = sSfxBankLerp[bankId].target;
}
}
}
void AudioSfx_ProcessActiveSfx(void) {
u8 bankId;
if (gAudioContext.seqPlayers[SEQ_PLAYER_SFX].enabled) {
sCurSfxPlayerChannelIndex = 0;
for (bankId = 0; bankId < ARRAY_COUNT(gSfxBanks); bankId++) {
AudioSfx_ChooseActiveSfx(bankId);
AudioSfx_PlayActiveSfx(bankId);
AudioSfx_StepBankLerp(bankId);
}
}
}
u8 AudioSfx_IsPlaying(u32 sfxId) {
SfxBankEntry* entry;
u8 entryIndex = gSfxBanks[SFX_BANK(sfxId)][0].next;
while (entryIndex != 0xFF) {
entry = &gSfxBanks[SFX_BANK(sfxId)][entryIndex];
if (entry->sfxId == sfxId) {
return true;
}
entryIndex = entry->next;
}
return false;
}
void AudioSfx_Reset(void) {
u8 bankId;
u8 i;
u8 entryIndex;
sSfxRequestWriteIndex = 0;
sSfxRequestReadIndex = 0;
sSfxChannelLowVolumeFlag = 0;
for (bankId = 0; bankId < ARRAY_COUNT(gSfxBanks); bankId++) {
sSfxBankListEnd[bankId] = 0;
sSfxBankFreeListStart[bankId] = 1;
sSfxBankUnused[bankId] = 0;
gSfxBankMuted[bankId] = false;
sSfxBankLerp[bankId].value = 1.0f;
sSfxBankLerp[bankId].remainingFrames = 0;
}
for (bankId = 0; bankId < ARRAY_COUNT(gSfxBanks); bankId++) {
for (i = 0; i < MAX_CHANNELS_PER_BANK; i++) {
gActiveSfx[bankId][i].entryIndex = 0xFF;
}
}
for (bankId = 0; bankId < ARRAY_COUNT(gSfxBanks); bankId++) {
gSfxBanks[bankId][0].prev = 0xFF;
gSfxBanks[bankId][0].next = 0xFF;
for (i = 1; i < sSfxBankSizes[bankId] - 1; i++) {
gSfxBanks[bankId][i].prev = i - 1;
gSfxBanks[bankId][i].next = i + 1;
}
gSfxBanks[bankId][i].prev = i - 1;
gSfxBanks[bankId][i].next = 0xFF;
}
}
+1 -1
View File
@@ -1,6 +1,6 @@
#include "global.h"
#pragma GLOBAL_ASM("asm/non_matchings/code/code_801A7B10/func_801A7B10.s")
#pragma GLOBAL_ASM("asm/non_matchings/code/code_801A7B10/Audio_StartSequence.s")
#pragma GLOBAL_ASM("asm/non_matchings/code/code_801A7B10/func_801A7D04.s")
+1 -1
View File
@@ -78,7 +78,7 @@ void AudioMgr_ThreadEntry(void* arg) {
s16* msg = NULL;
s32 exit;
func_801A4C30();
Audio_Init();
AudioLoad_SetDmaHandler(DmaMgr_DmaHandler);
func_801A4D00();
osSendMesg(&audioMgr->lockMsgQ, NULL, OS_MESG_BLOCK);
+1 -1
View File
@@ -9,7 +9,7 @@ void AudioMgr_StopAllSfxExceptSystem(void) {
for (bankIdPtr = sSfxBankIds; bankIdPtr < (sSfxBankIds + ARRAY_COUNT(sSfxBankIds)); bankIdPtr++) {
if (*bankIdPtr != BANK_SYSTEM) {
func_801A7084(*bankIdPtr);
AudioSfx_StopByBank(*bankIdPtr);
}
}
}
+5 -3
View File
@@ -2127,7 +2127,8 @@ void func_800B8E58(Player* player, u16 sfxId) {
if (player->currentMask == PLAYER_MASK_GIANT) {
func_8019F170(&player->actor.projectedPos, sfxId);
} else {
Audio_PlaySfxGeneral(sfxId, &player->actor.projectedPos, 4, &D_801DB4B0, &D_801DB4B0, &gSfxDefaultReverb);
AudioSfx_PlaySfx(sfxId, &player->actor.projectedPos, 4, &gSfxDefaultFreqAndVolScale,
&gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb);
}
}
@@ -2567,7 +2568,8 @@ void func_800B9D1C(Actor* actor) {
if (sfxId != 0) {
if (actor->audioFlags & 2) {
Audio_PlaySfxGeneral(sfxId, &actor->projectedPos, 4, &D_801DB4B0, &D_801DB4B0, &gSfxDefaultReverb);
AudioSfx_PlaySfx(sfxId, &actor->projectedPos, 4, &gSfxDefaultFreqAndVolScale, &gSfxDefaultFreqAndVolScale,
&gSfxDefaultReverb);
} else if (actor->audioFlags & 4) {
play_sound(sfxId);
} else if (actor->audioFlags & 8) {
@@ -3338,7 +3340,7 @@ Actor* Actor_Delete(ActorContext* actorCtx, Actor* actor, PlayState* play) {
actorCtx->targetContext.bgmEnemy = NULL;
}
Audio_StopSfxByPos(&actor->projectedPos);
AudioSfx_StopByPos(&actor->projectedPos);
Actor_Destroy(actor, play);
newHead = Actor_RemoveFromCategory(play, actorCtx, actor);
+2 -2
View File
@@ -59,11 +59,11 @@ EffectSs* EffectSS_GetTable() {
void EffectSS_Delete(EffectSs* effectSs) {
if (effectSs->flags & 2) {
Audio_StopSfxByPos(&effectSs->pos);
AudioSfx_StopByPos(&effectSs->pos);
}
if (effectSs->flags & 4) {
Audio_StopSfxByPos(&effectSs->vec);
AudioSfx_StopByPos(&effectSs->vec);
}
EffectSS_ResetEntry(effectSs);
+2 -2
View File
@@ -16,7 +16,7 @@ void SoundSource_UpdateAll(PlayState* play) {
for (i = 0; i < ARRAY_COUNT(play->soundSources); i++) {
if (source->countdown != 0) {
if (DECR(source->countdown) == 0) {
Audio_StopSfxByPos(&source->projectedPos);
AudioSfx_StopByPos(&source->projectedPos);
} else {
SkinMatrix_Vec3fMtxFMultXYZ(&play->viewProjectionMtxF, &source->worldPos, &source->projectedPos);
if (source->playSfxEachFrame) {
@@ -54,7 +54,7 @@ void SoundSource_Add(PlayState* play, Vec3f* worldPos, u32 duration, u16 sfxId,
// If no sound source is available, replace the sound source with the smallest remaining countdown
if (i >= ARRAY_COUNT(play->soundSources)) {
source = backupSource;
Audio_StopSfxByPos(&source->projectedPos);
AudioSfx_StopByPos(&source->projectedPos);
}
source->worldPos = *worldPos;