Add support for preset options to be used with BETTER_REVERB (#508)

* Bugfix: BETTER_REVERB starts before buffers are ready

* Add support for preset options to be used with BETTER_REVERB

* Some BETTER_REVERB cleanup

* The funny whoops

* Address suggested level script change

* Bugfix: useReverb crashes when disabled

* Allow window size override for vanilla-esque BETTER_REVERB presets

* Remove unnecessary downsampling limit check

* Fix up a few things + some slight reformatting

* Add light documentation to the BETTER_REVERB parameters

* Adjust BETTER_REVERB preset types to make more sense

* Reset BETTER_REVERB data buffer to be unallocated when not in use

* Properly disable BETTER_REVERB when disabling all reverb processing

* Remove an unnecessary BETTER_REVERB ifdef

* Remove D_80332108

* Revise BETTER_REVERB config description
This commit is contained in:
Gregory Heskett
2023-01-24 09:22:49 -05:00
committed by GitHub
parent d702f188c6
commit 7fdb5af8fd
25 changed files with 462 additions and 414 deletions

View File

@@ -38,6 +38,6 @@
/**
* Uses a much better implementation of reverb over vanilla's fake echo reverb. Great for caves or eerie levels, as well as just a better audio experience in general.
* Reverb parameters can be configured in audio/synthesis.c to meet desired aesthetic/performance needs. Currently US/JP only. Hurts emulator and console performance.
* Reverb presets can be configured in audio/data.c to meet desired aesthetic/performance needs. More detailed usage info can also be found on the HackerSM64 Wiki page.
*/
// #define BETTER_REVERB

View File

@@ -420,12 +420,30 @@ enum GoddardScene {
#define GAMMA(enabled) \
CMD_BBBB(LEVEL_CMD_SET_GAMMA, 0x04, enabled, 0x00)
#define SET_BACKGROUND_MUSIC(settingsPreset, seq) \
#ifdef BETTER_REVERB
#define SET_BACKGROUND_MUSIC_WITH_REVERB(settingsPreset, seq, reverbPresetConsole, reverbPresetEmulator) \
CMD_BBH(LEVEL_CMD_SET_MUSIC, 0x08, settingsPreset), \
CMD_HH(seq, 0x0000)
CMD_BBH(reverbPresetConsole, reverbPresetEmulator, seq)
#define SET_MENU_MUSIC_WITH_REVERB(seq, reverbPresetConsole, reverbPresetEmulator) \
CMD_BBH(LEVEL_CMD_SET_MENU_MUSIC, 0x08, seq), \
CMD_BBH(reverbPresetConsole, reverbPresetEmulator, 0x0000)
#else
// Functionally identical to calling SET_BACKGROUND_MUSIC if BETTER_REVERB is disabled
#define SET_BACKGROUND_MUSIC_WITH_REVERB(settingsPreset, seq, reverbPresetConsole, reverbPresetEmulator) \
CMD_BBH(LEVEL_CMD_SET_MUSIC, 0x08, settingsPreset), \
CMD_HH(0x0000, seq)
// Functionally identical to calling SET_MENU_MUSIC if BETTER_REVERB is disabled
#define SET_MENU_MUSIC_WITH_REVERB(seq, reverbPresetConsole, reverbPresetEmulator) \
CMD_BBH(LEVEL_CMD_SET_MENU_MUSIC, 0x04, seq)
#endif
#define SET_BACKGROUND_MUSIC(settingsPreset, seq) \
SET_BACKGROUND_MUSIC_WITH_REVERB(settingsPreset, seq, 0x00, 0x00)
#define SET_MENU_MUSIC(seq) \
CMD_BBH(LEVEL_CMD_SET_MENU_MUSIC, 0x04, seq)
SET_MENU_MUSIC_WITH_REVERB(seq, 0x00, 0x00)
#define STOP_MUSIC(fadeOutTime) \
CMD_BBH(LEVEL_CMD_FADEOUT_MUSIC, 0x04, fadeOutTime)

View File

@@ -16,22 +16,26 @@
#include "make_const_nonconst.h"
#include "levels/ending/header.h"
const LevelScript level_ending_entry[] = {
/*0*/ INIT_LEVEL(),
/*1*/ LOAD_LEVEL_DATA(ending),
/*4*/ ALLOC_LEVEL_POOL(),
/*5*/ AREA(/*index*/ 1, ending_geo_area_1),
/*7*/ END_AREA(),
/*8*/ FREE_LEVEL_POOL(),
/*9*/ SLEEP(/*frames*/ 60),
/*10*/ BLACKOUT(/*active*/ FALSE),
/*11*/ LOAD_AREA(/*area*/ 1),
/*12*/ TRANSITION(/*transType*/ WARP_TRANSITION_FADE_FROM_COLOR, /*time*/ 75, /*color*/ 0x00, 0x00, 0x00),
/*14*/ SLEEP(/*frames*/ 120),
/*15*/ CALL(/*arg*/ 0, /*func*/ lvl_play_the_end_screen_sound),
// L1:
/*17*/ SLEEP(/*frames*/ 1),
/*18*/ JUMP(level_ending_entry + 17), // goto L1 (loop sleep 1 forever)
const LevelScript level_ending_entry_loop[] = {
SLEEP(/*frames*/ 1),
JUMP(level_ending_entry_loop), // (loop sleep 1 forever)
};
const LevelScript level_ending_entry[] = {
INIT_LEVEL(),
LOAD_LEVEL_DATA(ending),
ALLOC_LEVEL_POOL(),
AREA(/*index*/ 1, ending_geo_area_1),
END_AREA(),
FREE_LEVEL_POOL(),
SLEEP(/*frames*/ 60),
BLACKOUT(/*active*/ FALSE),
LOAD_AREA(/*area*/ 1),
TRANSITION(/*transType*/ WARP_TRANSITION_FADE_FROM_COLOR, /*time*/ 75, /*color*/ 0x00, 0x00, 0x00),
SLEEP(/*frames*/ 120),
CALL(/*arg*/ 0, /*func*/ lvl_play_the_end_screen_sound),
JUMP(level_ending_entry_loop), // (loop sleep 1 forever)
};

View File

@@ -26,10 +26,10 @@
#include "game/object_list_processor.h"
const LevelScript level_intro_splash_screen[] = {
INIT_LEVEL(),
#ifdef SKIP_TITLE_SCREEN
EXIT_AND_EXECUTE_WITH_CODE(/*seg*/ SEGMENT_MENU_INTRO, _introSegmentRomStart, _introSegmentRomEnd, level_intro_mario_head_regular, _introSegmentBssStart, _introSegmentBssEnd),
#endif
INIT_LEVEL(),
LOAD_GODDARD(),
LOAD_BEHAVIOR_DATA(),
LOAD_LEVEL_DATA(intro),
@@ -48,6 +48,7 @@ const LevelScript level_intro_splash_screen[] = {
// Start animation
LOAD_AREA(/*area*/ 1),
SET_MENU_MUSIC(/*seq*/ SEQ_SOUND_PLAYER),
CALL(/*arg*/ LVL_INTRO_PLAY_ITS_A_ME_MARIO, /*func*/ lvl_intro_update),
CALL(/*arg*/ 0, /*func*/ load_mario_area),
@@ -70,6 +71,7 @@ const LevelScript level_intro_splash_screen[] = {
// Start animation
LOAD_AREA(/*area*/ 1),
SET_MENU_MUSIC(/*seq*/ SEQ_SOUND_PLAYER),
CALL(/*arg*/ LVL_INTRO_PLAY_ITS_A_ME_MARIO, /*func*/ lvl_intro_update),
SLEEP(/*frames*/ 75),
TRANSITION(/*transType*/ WARP_TRANSITION_FADE_INTO_COLOR, /*time*/ 16, /*color*/ 0x00, 0x00, 0x00),

View File

@@ -57,40 +57,44 @@ const LevelScript level_main_menu_entry_file_select[] = {
EXIT_AND_EXECUTE(/*seg*/ SEGMENT_GLOBAL_LEVEL_SCRIPT, _scriptsSegmentRomStart, _scriptsSegmentRomEnd, level_main_scripts_entry),
};
const LevelScript level_main_menu_entry_act_select_exit[] = {
EXIT(),
};
const LevelScript level_main_menu_entry_act_select[] = {
/* 0*/ CALL(/*arg*/ 0, /*func*/ lvl_set_current_level),
/* 2*/ JUMP_IF(/*op*/ OP_EQ, /*arg*/ FALSE, (level_main_menu_entry_act_select + 42)), // goto L1 (exit)
/* 5*/ INIT_LEVEL(),
/* 6*/ LOAD_GODDARD(),
/*10*/ LOAD_LEVEL_DATA(menu),
/*13*/ ALLOC_LEVEL_POOL(),
CALL(/*arg*/ 0, /*func*/ lvl_set_current_level),
JUMP_IF(/*op*/ OP_EQ, /*arg*/ FALSE, (level_main_menu_entry_act_select_exit)),
INIT_LEVEL(),
LOAD_GODDARD(),
LOAD_LEVEL_DATA(menu),
ALLOC_LEVEL_POOL(),
/*14*/ AREA(/*index*/ 2, geo_menu_act_selector_strings),
/*16*/ OBJECT(/*model*/ MODEL_NONE, /*pos*/ 0, -100, 0, /*angle*/ 0, 0, 0, /*behParam*/ BP(0x04, 0x00, 0x00, 0x00), /*beh*/ bhvActSelector),
/*22*/ TERRAIN(/*terrainData*/ main_menu_seg7_collision),
/*24*/ END_AREA(),
AREA(/*index*/ 2, geo_menu_act_selector_strings),
OBJECT(/*model*/ MODEL_NONE, /*pos*/ 0, -100, 0, /*angle*/ 0, 0, 0, /*behParam*/ BP(0x04, 0x00, 0x00, 0x00), /*beh*/ bhvActSelector),
TERRAIN(/*terrainData*/ main_menu_seg7_collision),
END_AREA(),
/*25*/ FREE_LEVEL_POOL(),
/*26*/ LOAD_AREA(/*area*/ 2),
FREE_LEVEL_POOL(),
LOAD_AREA(/*area*/ 2),
#ifdef NO_SEGMENTED_MEMORY
// sVisibleStars is set to 0 during FIXED_LOAD above on N64, but not when NO_SEGMENTED_MEMORY is used.
// lvl_init_act_selector_values_and_stars must be called here otherwise the previous
// value is retained and causes incorrect drawing during the 16 transition frames.
CALL(/*arg*/ 0, /*func*/ lvl_init_act_selector_values_and_stars),
#endif
/*27*/ TRANSITION(/*transType*/ WARP_TRANSITION_FADE_FROM_COLOR, /*time*/ 16, /*color*/ 0xFF, 0xFF, 0xFF),
/*29*/ SLEEP(/*frames*/ 16),
/*30*/ SET_MENU_MUSIC(/*seq*/ 0x000D),
TRANSITION(/*transType*/ WARP_TRANSITION_FADE_FROM_COLOR, /*time*/ 16, /*color*/ 0xFF, 0xFF, 0xFF),
SLEEP(/*frames*/ 16),
SET_MENU_MUSIC(/*seq*/ 0x000D),
#ifndef NO_SEGMENTED_MEMORY
/*31*/ CALL( /*arg*/ 0, /*func*/ lvl_init_act_selector_values_and_stars),
CALL( /*arg*/ 0, /*func*/ lvl_init_act_selector_values_and_stars),
#endif
/*33*/ CALL_LOOP(/*arg*/ 0, /*func*/ lvl_update_obj_and_load_act_button_actions),
/*35*/ GET_OR_SET(/*op*/ OP_SET, /*var*/ VAR_CURR_ACT_NUM),
/*36*/ STOP_MUSIC(/*fadeOutTime*/ 0x00BE),
/*37*/ TRANSITION(/*transType*/ WARP_TRANSITION_FADE_INTO_COLOR, /*time*/ 16, /*color*/ 0xFF, 0xFF, 0xFF),
/*39*/ SLEEP(/*frames*/ 16),
/*40*/ CLEAR_LEVEL(),
/*41*/ SLEEP_BEFORE_EXIT(/*frames*/ 1),
// L1:
/*42*/ EXIT(),
CALL_LOOP(/*arg*/ 0, /*func*/ lvl_update_obj_and_load_act_button_actions),
GET_OR_SET(/*op*/ OP_SET, /*var*/ VAR_CURR_ACT_NUM),
STOP_MUSIC(/*fadeOutTime*/ 0x00BE),
TRANSITION(/*transType*/ WARP_TRANSITION_FADE_INTO_COLOR, /*time*/ 16, /*color*/ 0xFF, 0xFF, 0xFF),
SLEEP(/*frames*/ 16),
CLEAR_LEVEL(),
SLEEP_BEFORE_EXIT(/*frames*/ 1),
EXIT(),
};

View File

@@ -41,6 +41,71 @@ struct AudioSessionSettingsEU gAudioSessionPresets[] = {
};
#endif
#ifdef BETTER_REVERB
// Each entry represents an array of variable audio buffer sizes / delays for each respective filter.
u32 delaysArr[][NUM_ALLPASS] = {
{ /* 0 */
4, 4, 4,
4, 4, 4,
4, 4, 4,
4, 4, 4
},
{ /* 1 */
1080, 1352, 1200,
1200, 1232, 1432,
1384, 1048, 1352,
928, 1504, 1512
},
{ /* 2 */
1384, 1352, 1048,
928, 1512, 1504,
1080, 1200, 1352,
1200, 1432, 1232
},
};
// Each entry represents an array of multipliers applied to the final output of each group of 3 filters.
// These values are u8s in spirit, but are set as s32 values to slightly increase performance during calculations.
s32 reverbMultsArr[][NUM_ALLPASS / 3] = {
/* 0 */ {0x00, 0x00, 0x00, 0x00},
/* 1 */ {0xD7, 0x6F, 0x36, 0x22},
/* 2 */ {0xCF, 0x73, 0x38, 0x1F},
};
/**
* Format:
* - downsampleRate (Higher values exponentially reduce the number of input samples to process, improving perfomance at cost of quality)
* - isMono (Only process reverb on the left channel and share it with the right channel, improving performance at cost of quality)
* - filterCount (Number of filters to process data with; in general, more filters means higher quality at the cost of performance demand)
* - windowSize (Size of circular reverb buffer; higher values work better for a more open soundscape, lower is better for a more compact sound)
* - gain (Amount of audio retransmitted into the circular reverb buffer, emulating decay; higher values represent a lengthier decay period)
* - gainIndex (Advanced parameter used to tune the outputs of every first two of three filters)
* - reverbIndex (Advanced parameter used to tune the incoming output of every third filter)
*
* - *delaysL (Array of variable audio buffer sizes / delays for each respective filter [left channel])
* - *delaysR (Array of variable audio buffer sizes / delays for each respective filter [right channel])
* - *reverbMultsL (Array of multipliers applied to the final output of each group of 3 filters [left channel])
* - *reverbMultsR (Array of multipliers applied to the final output of each group of 3 filters [right channel])
*
* NOTE: First entry will always be used by default when not using the level commands to specify a preset.
* Please reference the HackerSM64 Wiki for more descriptive documentation of these parameters and usage of BETTER_REVERB in general.
*/
struct BetterReverbSettings gBetterReverbSettings[] = {
{ /* 0 */
-1, FALSE, NUM_ALLPASS, -1, -1, 0x00, 0x00, // Vanilla Reverb
delaysArr[0], delaysArr[0], reverbMultsArr[0], reverbMultsArr[0]
},
{ /* 1 */
2, FALSE, (NUM_ALLPASS - 9), 0xE00, 0x43FF, 0xA0, 0x30, // Default Console
delaysArr[1], delaysArr[2], reverbMultsArr[1], reverbMultsArr[2]
},
{ /* 2 */
1, FALSE, NUM_ALLPASS, 0xE00, 0x28FF, 0xA0, 0x60, // Default Emulator (RCVI Hack only)
delaysArr[1], delaysArr[2], reverbMultsArr[1], reverbMultsArr[2]
},
};
#endif
// Format:
// - frequency
// - max number of simultaneous notes
@@ -76,10 +141,9 @@ struct ReverbSettingsUS gReverbSettings[18] = {
{ 1, 0x0800, 0x2FFF },
};
struct AudioSessionSettings gAudioSessionPresets[1] = {
{ 32000, MAX_SIMULTANEOUS_NOTES, 1, 0x1000, 0x2FFF, 0x7FFF, PERSISTENT_SEQ_MEM, PERSISTENT_BANK_MEM, TEMPORARY_SEQ_MEM, TEMPORARY_BANK_MEM },
};
struct AudioSessionSettings gAudioSessionSettings = { 32000, MAX_SIMULTANEOUS_NOTES, 0x7FFF, PERSISTENT_SEQ_MEM, PERSISTENT_BANK_MEM, TEMPORARY_SEQ_MEM, TEMPORARY_BANK_MEM };
#endif
// gAudioCosineTable[k] = round((2**15 - 1) * cos(pi/2 * k / 127)). Unused.
#if defined(VERSION_JP) || defined(VERSION_US)
u16 gAudioCosineTable[128] = {

View File

@@ -44,10 +44,12 @@
extern struct AudioSessionSettingsEU gAudioSessionPresets[];
extern struct ReverbSettingsEU sReverbSettings[8];
#else
extern struct AudioSessionSettings gAudioSessionPresets[1];
extern struct AudioSessionSettings gAudioSessionSettings;
extern struct ReverbSettingsUS gReverbSettings[18];
#endif
extern u16 D_80332388[128]; // unused
#ifdef BETTER_REVERB
extern struct BetterReverbSettings gBetterReverbSettings[];
#endif
#if defined(VERSION_EU) || defined(VERSION_SH)
extern f32 gPitchBendFrequencyScale[256];

View File

@@ -326,7 +326,6 @@ u8 sMaxChannelsForSoundBank[SOUND_BANK_COUNT] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }
f32 gGlobalSoundSource[3] = { 0.0f, 0.0f, 0.0f };
u8 sSoundBankDisabled[16] = { 0 };
u8 D_80332108 = 0;
u8 sHasStartedFadeOut = FALSE;
u16 sSoundBanksThatLowerBackgroundMusic = 0;
u8 sBackgroundMusicMaxTargetVolume = TARGET_VOLUME_UNSET;
@@ -2505,9 +2504,9 @@ void play_toads_jingle(void) {
/**
* Called from threads: thread5_game_loop
*/
void sound_reset(u8 presetId) {
if (presetId >= 8) {
presetId = 0;
void sound_reset(u8 reverbPresetId) {
if (reverbPresetId >= ARRAY_COUNT(gReverbSettings)) {
reverbPresetId = 0;
}
sGameLoopTicked = 0;
disable_all_sequence_players();
@@ -2516,26 +2515,16 @@ void sound_reset(u8 presetId) {
func_802ad74c(0xF2000000, 0);
#endif
#if defined(VERSION_JP) || defined(VERSION_US)
audio_reset_session(&gAudioSessionPresets[0], presetId);
audio_reset_session(reverbPresetId);
#else
audio_reset_session_eu(presetId);
audio_reset_session_eu(reverbPresetId);
#endif
osWritebackDCacheAll();
if (presetId != 7) {
if (reverbPresetId != 7) {
preload_sequence(SEQ_EVENT_SOLVE_PUZZLE, PRELOAD_BANKS | PRELOAD_SEQUENCE);
preload_sequence(SEQ_EVENT_PEACH_MESSAGE, PRELOAD_BANKS | PRELOAD_SEQUENCE);
preload_sequence(SEQ_EVENT_CUTSCENE_STAR_SPAWN, PRELOAD_BANKS | PRELOAD_SEQUENCE);
}
seq_player_play_sequence(SEQ_PLAYER_SFX, SEQ_SOUND_PLAYER, 0);
D_80332108 = (D_80332108 & 0xf0) + presetId;
gSoundMode = D_80332108 >> 4;
sHasStartedFadeOut = FALSE;
}
/**
* Called from threads: thread5_game_loop
*/
void audio_set_sound_mode(u8 soundMode) {
D_80332108 = (D_80332108 & 0xf) + (soundMode << 4);
gSoundMode = soundMode;
}

View File

@@ -66,8 +66,7 @@ void play_star_fanfare(void);
void play_power_star_jingle(void);
void play_race_fanfare(void);
void play_toads_jingle(void);
void sound_reset(u8 presetId);
void audio_set_sound_mode(u8 soundMode);
void sound_reset(u8 reverbPresetId);
void audio_init(void); // in load.c

View File

@@ -9,6 +9,7 @@
#include "game/game_init.h"
#include "game/puppyprint.h"
#include "game/vc_check.h"
#include "game/debug.h"
#include "string.h"
struct PoolSplit {
@@ -983,7 +984,7 @@ void init_reverb_eu(void) {
// This is called 4 times for numReverbs to work at higher values. This does eat up some memory though.
for (j = 0; j < 4; j++) {
gSynthesisReverbs[j].useReverb = 0;
gSynthesisReverbs[j].useReverb = FALSE;
// Both left and right channels are allocated/cleared together, then separated based on the reverb window size
if (!sAudioIsInitialized) {
@@ -997,7 +998,7 @@ void init_reverb_eu(void) {
reverb->windowSize = (reverbSettings->windowSize * 0x40);
reverb->downsampleRate = reverbSettings->downsampleRate;
reverb->reverbGain = reverbSettings->gain;
reverb->useReverb = 8;
reverb->useReverb = TRUE;
if (reverb->windowSize > REVERB_WINDOW_SIZE_MAX) {
reverb->windowSize = REVERB_WINDOW_SIZE_MAX;
}
@@ -1043,105 +1044,115 @@ void init_reverb_eu(void) {
void init_reverb_us(s32 presetId) {
s16 *mem;
s32 i;
#ifdef BETTER_REVERB
s8 reverbConsole;
#endif
s32 reverbWindowSize = gReverbSettings[presetId].windowSize;
gReverbDownsampleRate = gReverbSettings[presetId].downsampleRate;
#ifdef BETTER_REVERB
if (gIsConsole) {
reverbConsole = betterReverbDownsampleConsole; // Console!
} else {
reverbConsole = betterReverbDownsampleEmulator; // Setting this to 1 is REALLY slow, please use sparingly!
}
if (reverbConsole <= 0) {
reverbConsole = 1;
// This will likely crash if given an invalid preset value. Adding a safety check here isn't worth the usability interference.
struct BetterReverbSettings *betterReverbPreset = &gBetterReverbSettings[gBetterReverbPreset];
betterReverbDownsampleRate = betterReverbPreset->downsampleRate;
monoReverb = betterReverbPreset->isMono;
reverbFilterCount = betterReverbPreset->filterCount;
betterReverbWindowsSize = betterReverbPreset->windowSize;
betterReverbRevIndex = betterReverbPreset->reverbIndex;
betterReverbGainIndex = betterReverbPreset->gainIndex;
gReverbMultsL = betterReverbPreset->reverbMultsL;
gReverbMultsR = betterReverbPreset->reverbMultsR;
if (betterReverbDownsampleRate <= 0) {
toggleBetterReverb = FALSE;
if (betterReverbWindowsSize >= 0)
reverbWindowSize = betterReverbWindowsSize;
} else {
toggleBetterReverb = TRUE;
gReverbDownsampleRate = (1 << (betterReverbDownsampleRate - 1));
if (betterReverbWindowsSize >= 0) {
reverbWindowSize = betterReverbWindowsSize;
reverbWindowSize /= gReverbDownsampleRate;
if (reverbWindowSize < DEFAULT_LEN_2CH && betterReverbWindowsSize != 0) // Minimum window size to not overflow
reverbWindowSize = DEFAULT_LEN_2CH;
}
}
if (toggleBetterReverb && betterReverbWindowsSize >= 0) {
reverbWindowSize = betterReverbWindowsSize;
}
if (gReverbDownsampleRate < (1 << (reverbConsole - 1))) {
gReverbDownsampleRate = (1 << (reverbConsole - 1));
}
reverbWindowSize /= gReverbDownsampleRate;
if (reverbWindowSize < DEFAULT_LEN_2CH) { // Minimum window size to not overflow
reverbWindowSize = DEFAULT_LEN_2CH;
reverbFilterCount -= reverbFilterCount % 3;
if (reverbFilterCount > NUM_ALLPASS) {
reverbFilterCount = NUM_ALLPASS;
} else if (reverbFilterCount < 3) {
reverbFilterCount = 3;
}
#endif
if (reverbWindowSize == 0) {
gSynthesisReverb.useReverb = 0;
if (reverbWindowSize > 0)
gSynthesisReverb.useReverb = TRUE;
else
gSynthesisReverb.useReverb = FALSE;
if (reverbWindowSize > REVERB_WINDOW_SIZE_MAX) {
reverbWindowSize = REVERB_WINDOW_SIZE_MAX;
}
// Both left and right channels are allocated/cleared together, then separated based on the reverb window size
if (!sAudioIsInitialized) {
gSynthesisReverb.ringBuffer.left = soundAlloc(&gNotesAndBuffersPool, REVERB_WINDOW_SIZE_MAX * 2 * sizeof(s16));
gSynthesisReverb.resampleStateLeft = soundAlloc(&gNotesAndBuffersPool, (16 * sizeof(s16)));
gSynthesisReverb.resampleStateRight = soundAlloc(&gNotesAndBuffersPool, (16 * sizeof(s16)));
gSynthesisReverb.unk24 = soundAlloc(&gNotesAndBuffersPool, (16 * sizeof(s16)));
gSynthesisReverb.unk28 = soundAlloc(&gNotesAndBuffersPool, (16 * sizeof(s16)));
for (i = 0; i < gAudioUpdatesPerFrame; i++) {
mem = soundAlloc(&gNotesAndBuffersPool, DEFAULT_LEN_2CH);
gSynthesisReverb.items[0][i].toDownsampleLeft = mem;
gSynthesisReverb.items[0][i].toDownsampleRight = (mem + (DEFAULT_LEN_1CH / sizeof(s16)));
mem = soundAlloc(&gNotesAndBuffersPool, DEFAULT_LEN_2CH);
gSynthesisReverb.items[1][i].toDownsampleLeft = mem;
gSynthesisReverb.items[1][i].toDownsampleRight = (mem + (DEFAULT_LEN_1CH / sizeof(s16)));
}
} else {
gSynthesisReverb.useReverb = 8;
if (reverbWindowSize > REVERB_WINDOW_SIZE_MAX) {
reverbWindowSize = REVERB_WINDOW_SIZE_MAX;
}
// Both left and right channels are allocated/cleared together, then separated based on the reverb window size
if (!sAudioIsInitialized) {
gSynthesisReverb.ringBuffer.left = soundAlloc(&gNotesAndBuffersPool, REVERB_WINDOW_SIZE_MAX * 2 * sizeof(s16));
gSynthesisReverb.resampleStateLeft = soundAlloc(&gNotesAndBuffersPool, (16 * sizeof(s16)));
gSynthesisReverb.resampleStateRight = soundAlloc(&gNotesAndBuffersPool, (16 * sizeof(s16)));
gSynthesisReverb.unk24 = soundAlloc(&gNotesAndBuffersPool, (16 * sizeof(s16)));
gSynthesisReverb.unk28 = soundAlloc(&gNotesAndBuffersPool, (16 * sizeof(s16)));
for (i = 0; i < gAudioUpdatesPerFrame; i++) {
mem = soundAlloc(&gNotesAndBuffersPool, DEFAULT_LEN_2CH);
gSynthesisReverb.items[0][i].toDownsampleLeft = mem;
gSynthesisReverb.items[0][i].toDownsampleRight = (mem + (DEFAULT_LEN_1CH / sizeof(s16)));
mem = soundAlloc(&gNotesAndBuffersPool, DEFAULT_LEN_2CH);
gSynthesisReverb.items[1][i].toDownsampleLeft = mem;
gSynthesisReverb.items[1][i].toDownsampleRight = (mem + (DEFAULT_LEN_1CH / sizeof(s16)));
}
#ifdef BETTER_REVERB
initialize_better_reverb_buffers();
#endif
} else {
bzero(gSynthesisReverb.ringBuffer.left, (REVERB_WINDOW_SIZE_MAX * 2 * sizeof(s16)));
}
gSynthesisReverb.ringBuffer.right = &gSynthesisReverb.ringBuffer.left[reverbWindowSize];
gSynthesisReverb.nextRingBufferPos = 0;
gSynthesisReverb.unkC = 0;
gSynthesisReverb.curFrame = 0;
gSynthesisReverb.bufSizePerChannel = reverbWindowSize;
gSynthesisReverb.reverbGain = gReverbSettings[presetId].gain;
gSynthesisReverb.framesLeftToIgnore = 2;
if (gReverbDownsampleRate != 1) {
gSynthesisReverb.resampleFlags = A_INIT;
gSynthesisReverb.resampleRate = (0x8000 / gReverbDownsampleRate);
if (sAudioIsInitialized) {
bzero(gSynthesisReverb.resampleStateLeft, (16 * sizeof(s16)));
bzero(gSynthesisReverb.resampleStateRight, (16 * sizeof(s16)));
bzero(gSynthesisReverb.unk24, (16 * sizeof(s16)));
bzero(gSynthesisReverb.unk28, (16 * sizeof(s16)));
// All reverb downsample buffers are adjacent in memory, so clear them all in a single call
bzero(gSynthesisReverb.items[0][0].toDownsampleLeft, (DEFAULT_LEN_1CH * 4 * gAudioUpdatesPerFrame));
}
}
// This does not have to be reset after being initialized for the first time, which would speed up load times dramatically.
// However, reseting this allows for proper clearing of the reverb buffers, as well as dynamic customization of the delays array.
#ifdef BETTER_REVERB
if (toggleBetterReverb) {
if (sAudioIsInitialized) {
clear_better_reverb_buffers();
}
set_better_reverb_buffers();
}
#endif
bzero(gSynthesisReverb.ringBuffer.left, (REVERB_WINDOW_SIZE_MAX * 2 * sizeof(s16)));
}
gSynthesisReverb.ringBuffer.right = &gSynthesisReverb.ringBuffer.left[reverbWindowSize];
gSynthesisReverb.nextRingBufferPos = 0;
gSynthesisReverb.unkC = 0;
gSynthesisReverb.curFrame = 0;
gSynthesisReverb.bufSizePerChannel = reverbWindowSize;
gSynthesisReverb.reverbGain = gReverbSettings[presetId].gain;
gSynthesisReverb.framesLeftToIgnore = 2;
if (gReverbDownsampleRate != 1) {
gSynthesisReverb.resampleFlags = A_INIT;
gSynthesisReverb.resampleRate = (0x8000 / gReverbDownsampleRate);
if (sAudioIsInitialized) {
bzero(gSynthesisReverb.resampleStateLeft, (16 * sizeof(s16)));
bzero(gSynthesisReverb.resampleStateRight, (16 * sizeof(s16)));
bzero(gSynthesisReverb.unk24, (16 * sizeof(s16)));
bzero(gSynthesisReverb.unk28, (16 * sizeof(s16)));
// All reverb downsample buffers are adjacent in memory, so clear them all in a single call
bzero(gSynthesisReverb.items[0][0].toDownsampleLeft, (DEFAULT_LEN_1CH * 4 * gAudioUpdatesPerFrame));
}
}
#ifdef BETTER_REVERB
if (!gSynthesisReverb.useReverb)
toggleBetterReverb = FALSE;
if (betterReverbPreset->gain > 0)
gSynthesisReverb.reverbGain = (u16) betterReverbPreset->gain;
if (!sAudioIsInitialized)
initialize_better_reverb_buffers();
// This does not have to be reset after being initialized for the first time, which would help speed up load times.
// However, resetting this allows for proper clearing of the reverb buffers, as well as dynamic customization of the delays array.
set_better_reverb_buffers(betterReverbPreset->delaysL, betterReverbPreset->delaysR);
#endif
}
#endif
#if defined(VERSION_JP) || defined(VERSION_US)
void audio_reset_session(struct AudioSessionSettings *preset, s32 presetId) {
void audio_reset_session(s32 reverbPresetId) {
if (sAudioIsInitialized) {
if (gAudioLoadLock != AUDIO_LOCK_UNINITIALIZED) {
gAudioLoadLock = AUDIO_LOCK_LOADING;
@@ -1163,7 +1174,7 @@ void audio_reset_session(struct AudioSessionSettings *preset, s32 presetId) {
temporary_pool_clear( &gBankLoadedPool.temporary);
reset_bank_and_seq_load_status();
init_reverb_us(presetId);
init_reverb_us(reverbPresetId);
bzero(&gAiBuffers[0][0], (AIBUFFER_LEN * NUMAIBUFFERS));
if (gAudioLoadLock != AUDIO_LOCK_UNINITIALIZED) {
@@ -1319,11 +1330,11 @@ void audio_reset_session(void) {
gMaxAudioCmds = gMaxSimultaneousNotes * 0x10 * gAudioBufferParameters.updatesPerFrame + preset->numReverbs * 0x20 + 0x300;
#endif
#else
gAiFrequency = osAiSetFrequency(preset->frequency);
gMaxSimultaneousNotes = preset->maxSimultaneousNotes;
gAiFrequency = osAiSetFrequency(gAudioSessionSettings.frequency);
gMaxSimultaneousNotes = gAudioSessionSettings.maxSimultaneousNotes;
gSamplesPerFrameTarget = ALIGN16(gAiFrequency / 60);
gVolume = preset->volume;
gVolume = gAudioSessionSettings.volume;
gMinAiBufferLength = gSamplesPerFrameTarget - 0x10;
gAudioUpdatesPerFrame = updatesPerFrame = gSamplesPerFrameTarget / 160 + 1;
@@ -1352,8 +1363,8 @@ void audio_reset_session(void) {
persistentMem = DOUBLE_SIZE_ON_64_BIT(preset->persistentSeqMem + preset->persistentBankMem + preset->unk18 + preset->unkMem28 + 0x10);
temporaryMem = DOUBLE_SIZE_ON_64_BIT(preset->temporarySeqMem + preset->temporaryBankMem + preset->unk24 + preset->unkMem2C + 0x10);
#else
persistentMem = DOUBLE_SIZE_ON_64_BIT(preset->persistentSeqMem + preset->persistentBankMem);
temporaryMem = DOUBLE_SIZE_ON_64_BIT(preset->temporarySeqMem + preset->temporaryBankMem);
persistentMem = DOUBLE_SIZE_ON_64_BIT(gAudioSessionSettings.persistentSeqMem + gAudioSessionSettings.persistentBankMem);
temporaryMem = DOUBLE_SIZE_ON_64_BIT(gAudioSessionSettings.temporarySeqMem + gAudioSessionSettings.temporaryBankMem);
#endif
totalMem = persistentMem + temporaryMem;
wantMisc = gAudioSessionPool.size - totalMem - BETTER_REVERB_SIZE;
@@ -1363,16 +1374,16 @@ void audio_reset_session(void) {
sSeqAndBankPoolSplit.wantPersistent = persistentMem;
sSeqAndBankPoolSplit.wantTemporary = temporaryMem;
seq_and_bank_pool_init(&sSeqAndBankPoolSplit);
sPersistentCommonPoolSplit.wantSeq = DOUBLE_SIZE_ON_64_BIT(preset->persistentSeqMem);
sPersistentCommonPoolSplit.wantBank = DOUBLE_SIZE_ON_64_BIT(preset->persistentBankMem);
sPersistentCommonPoolSplit.wantSeq = DOUBLE_SIZE_ON_64_BIT(gAudioSessionSettings.persistentSeqMem);
sPersistentCommonPoolSplit.wantBank = DOUBLE_SIZE_ON_64_BIT(gAudioSessionSettings.persistentBankMem);
#ifdef VERSION_SH
sPersistentCommonPoolSplit.wantUnused = preset->unk18;
#else
sPersistentCommonPoolSplit.wantUnused = 0;
#endif
persistent_pools_init(&sPersistentCommonPoolSplit);
sTemporaryCommonPoolSplit.wantSeq = DOUBLE_SIZE_ON_64_BIT(preset->temporarySeqMem);
sTemporaryCommonPoolSplit.wantBank = DOUBLE_SIZE_ON_64_BIT(preset->temporaryBankMem);
sTemporaryCommonPoolSplit.wantSeq = DOUBLE_SIZE_ON_64_BIT(gAudioSessionSettings.temporarySeqMem);
sTemporaryCommonPoolSplit.wantBank = DOUBLE_SIZE_ON_64_BIT(gAudioSessionSettings.temporaryBankMem);
#ifdef VERSION_SH
sTemporaryCommonPoolSplit.wantUnused = preset->unk24;
#else
@@ -1404,7 +1415,7 @@ void audio_reset_session(void) {
init_reverb_eu();
#else
init_reverb_us(presetId);
init_reverb_us(reverbPresetId);
#endif
init_sample_dma_buffers(gMaxSimultaneousNotes);

View File

@@ -142,7 +142,7 @@ void *get_bank_or_seq(struct SoundMultiPool *arg0, s32 arg1, s32 id);
s32 audio_shut_down_and_reset_step(void);
void audio_reset_session(void);
#else
void audio_reset_session(struct AudioSessionSettings *preset, s32 presetId);
void audio_reset_session(s32 reverbPresetId);
#endif
void discard_bank(s32 bankId);

View File

@@ -730,6 +730,22 @@ struct NoteSynthesisBuffers {
#endif
};
#ifdef BETTER_REVERB
struct BetterReverbSettings {
s8 downsampleRate;
u8 isMono;
u8 filterCount;
s16 windowSize;
s16 gain;
u8 gainIndex;
u8 reverbIndex;
u32 *delaysL;
u32 *delaysR;
s32 *reverbMultsL;
s32 *reverbMultsR;
};
#endif
#ifdef VERSION_EU
struct ReverbSettingsEU {
u8 downsampleRate;
@@ -781,15 +797,12 @@ struct AudioSessionSettingsEU {
struct AudioSessionSettings {
/*0x00*/ u32 frequency;
/*0x04*/ u8 maxSimultaneousNotes;
/*0x05*/ u8 reverbDownsampleRate; // always 1
/*0x06*/ u16 reverbWindowSize;
/*0x08*/ u16 reverbGain;
/*0x0A*/ u16 volume;
/*0x0C*/ u32 persistentSeqMem;
/*0x10*/ u32 persistentBankMem;
/*0x14*/ u32 temporarySeqMem;
/*0x18*/ u32 temporaryBankMem;
}; // size = 0x1C
/*0x06*/ u16 volume;
/*0x08*/ u32 persistentSeqMem;
/*0x0C*/ u32 persistentBankMem;
/*0x10*/ u32 temporarySeqMem;
/*0x14*/ u32 temporaryBankMem;
}; // size = 0x18
struct AudioBufferParametersEU {
/*0x00*/ s16 presetUnk4; // audio frames per vsync?

View File

@@ -879,7 +879,7 @@ void audio_init() {
gAudioResetStatus = 1;
audio_shut_down_and_reset_step();
#else
audio_reset_session(&gAudioSessionPresets[0], 0);
audio_reset_session(0);
#endif
// Not sure about these prints

View File

@@ -153,7 +153,7 @@ void eu_process_audio_cmd(struct EuAudioCmd *cmd) {
break;
case 0xf0:
gSoundMode = cmd->u2.as_s32;
// gSoundMode = cmd->u2.as_s32; // Commenting this out, as the way to reset this has been removed.
break;
case 0xf1:

View File

@@ -176,7 +176,7 @@ void eu_process_audio_cmd(struct EuAudioCmd *cmd) {
break;
case 0xf0:
gSoundMode = cmd->u2.as_s32;
// gSoundMode = cmd->u2.as_s32; // Commenting this out, as the way to reset this has been removed.
break;
case 0xf1:

View File

@@ -9,6 +9,7 @@
#include "internal.h"
#include "external.h"
#include "game/game_init.h"
#include "game/debug.h"
#include "engine/math_util.h"
@@ -40,122 +41,26 @@
#define AUDIO_ALIGN(val, amnt) (((val) + (1 << amnt) - 1) & ~((1 << amnt) - 1))
#ifdef BETTER_REVERB
/* ----------------------------------------------------------------------BEGIN REVERB PARAMETERS---------------------------------------------------------------------- */
/**
* This reverb is a much more natural, ambient implementation over vanilla's, though at the cost of some memory and performance.
* These parameters are here to provide maximum control over the usage of the reverb effect, as well as with game performance.
*
* To take advantage of the reverb effect, you can change the echo parameters set in levels/level_defines.h to tailor the reverb to each specific level area.
* To adjust reverb presence with individual sound effects, apply the .set_reverb command within sound/sequences/00_sound_player.s (see examples of other sounds that use it).
* To use with M64 sequences, set the Effect parameter for each channel accordingly (CC 91 for MIDI files).
*
* Most parameter configuration is to be done here, though BETTER_REVERB_SIZE can be adjusted in audio/synthesis.h.
*
* If after changing the parameters, you hear increasing noise followed by a sudden disappearance of reverb and/or scratchy audio, this indicates an s16 overflow.
* If this happens, stop immediately and reduce the parameters at fault. This becomes a ticking time bomb, and may eventually result in very loud noise if it reaches the point of s32 overflow.
* Depending on the violating parameters chosen, you probably won't ever experience s32 overflow, but s16 overflow still isn't a pleasant experience.
* Checks to prevent this have not been implemented to maximize performance potential, so choose your parameters wisely. The current defaults are unlikely to have this problem.
* Generally speaking, a sound that doesn't seem to be fading at a natural rate is a parameter red flag (also known as feedback).
*
* This is also known to cause severe lag on emulators that have counter factor set to 2 or greater.
* If this is an issue, it is recommended you enable RCVI hack in the config files. Alternatively, you can reduce the reverb parameters here to compensate.
*/
// Larger values downsample the reverb exponentially by multiples of 2. A value of 1 doesn't downsample at all. This can substantially increase performance at the cost of resolution.
// Setting this to 4 corrupts the game, so set this value to -1 to use vanilla reverb if this is too slow, or if it just doesn't fit the desired aesthetic of a level.
// You can change this value before audio_reset_session gets called if different levels can tolerate the demand better than others or just have different reverb goals.
// A higher downsample value hits the game's frequency limit sooner, which can cause the reverb sometimes to be off pitch. This is a vanilla quirk (and also counter intuitive).
// Higher downsample values also result in slightly shorter reverb decay times, so keep this in mind if balancing reverb presence with emulator, or maybe consider adjusting REVERB_REV_INDEX with a console check.
s8 betterReverbDownsampleConsole = 2;
// Larger values downsample the reverb exponentially by multiples of 2. A value of 1 doesn't downsample at all. This can substantially increase performance at the cost of resolution.
// Most emulators can handle a default value of 2, but 3 may be advisable as a failsafe against a counter factor of 2 (if RCVI hack is disabled). Setting this to -1 also uses vanilla reverb.
// Using a value of 1 is not recommended on emulator unless RCVI hack is enabled or other parameters are reduced to compensate. If you do decide to use 1 here, you must adjust BETTER_REVERB_SIZE appropriately.
// You can change this value before audio_reset_session gets called if different levels can tolerate the demand better than others or just have different reverb goals.
// A higher downsample value hits the game's frequency limit sooner, which can cause the reverb sometimes to be off pitch. This is a vanilla quirk (and also counter intuitive).
// Higher downsample values also result in slightly shorter reverb decay times, so keep this in mind if balancing reverb presence with console, or maybe consider adjusting REVERB_REV_INDEX with a console check.
s8 betterReverbDownsampleEmulator = 2;
// This value represents the number of filters to use with the reverb. This can be decreased to improve performance, but at the cost of a lesser presence of reverb in the final audio.
// Filter count should always be a multiple of 3. Never ever set this value to be greater than NUM_ALLPASS.
// This value cannot be less than 3. Setting it to anything lower will act as if it was set to 3.
// This can be changed at any time, but is best set immediately before calling audio_reset_session.
s32 reverbFilterCountConsole = (NUM_ALLPASS - 9);
// This value represents the number of filters to use with the reverb. This can be decreased to improve performance, but at the cost of a lesser presence of reverb in the final audio.
// Filter count should always be a multiple of 3. Never ever set this value to be greater than NUM_ALLPASS.
// This value cannot be less than 3. Setting it to anything lower will act as if it was set to 3.
// This can be changed at any time, but is best set immediately before calling audio_reset_session.
s32 reverbFilterCountEmulator = NUM_ALLPASS;
// Set this to TRUE to use mono over stereo for reverb. This should increase performance, but at the cost of a less fulfilling reverb experience.
// If performance is desirable, it is recommended to change reverbFilterCountConsole or betterReverbDownsampleConsole first.
// This can be changed at any time, but is best set immediately before calling audio_reset_session.
u8 monoReverbConsole = FALSE;
// Set this to TRUE to use mono over stereo for reverb. This should increase performance, but at the cost of a less fulfilling reverb experience.
// If performance is desirable, it is recommended to change reverbFilterCountEmulator or betterReverbDownsampleEmulator first.
// This can be changed at any time, but is best set immediately before calling audio_reset_session.
u8 monoReverbEmulator = FALSE;
// This value controls the size of the reverb buffer. It affects the global reverb delay time. This variable is one of the easiest to control.
// Setting the value lower than the downsample buffer size will destroy the game audio. This is taken into account automatically, but also means the value set here isn't what always gets used.
// Similarly, this value maxes out at (REVERB_WINDOW_SIZE_MAX * 2^(downsample factor - 1)).
// If this value is changed, it will go into effect the next time audio_reset_session is called.
// Set to -1 to use a default preset instead. Higher values represent more audio delay (usually better for echoey spaces).
s32 betterReverbWindowsSize = -1;
// These are set to defines rather than variables to increase performance. Change these to s32 if you want them to be configurable in-game. (Maybe extern them in synthesis.h)
// Setting these to values larger than 0xFF (255) or less than 0 may cause issues and is not recommended.
#define REVERB_REV_INDEX 0x60 // Affects decay time mostly (large values can cause terrible feedback!); can be messed with at any time
#define REVERB_GAIN_INDEX 0xA0 // Affects signal immediately retransmitted back into buffers (mid-high values yield the strongest effect); can be messed with at any time
#define REVERB_WET_SIGNAL 0xE0 // Amount of reverb specific output in final signal (also affects decay); can be messed with at any time, also very easy to control
// #define REVERB_DRY_SIGNAL = 0x00; // Amount of original input in final signal (large values can cause terrible feedback!); declaration and uses commented out by default to improve compiler optimization
/* ---------------------------------------------------------------------ADVANCED REVERB PARAMETERS-------------------------------------------------------------------- */
// These values affect filter delays. Bigger values will result in fatter echo (and more memory); must be cumulatively smaller than BETTER_REVERB_SIZE/2.
// If setting a reverb downsample value to 1, these must be cumulatively smaller than BETTER_REVERB_SIZE/4.
// None of the delay values should ever be smaller than 1; these are s32s purely to avoid typecasts.
// These values are applied any time audio_reset_session is called, and as such can be changed at any time without issues.
s32 delaysBaselineL[NUM_ALLPASS] = {
1080, 1352, 1200,
1200, 1232, 1432,
1384, 1048, 1352,
928, 1504, 1512
};
s32 delaysBaselineR[NUM_ALLPASS] = {
1384, 1352, 1048,
928, 1512, 1504,
1080, 1200, 1352,
1200, 1432, 1232
};
// These values affect reverb decay depending on the filter index; can be messed with at any time, and will have effects updated in real time
s32 gReverbMultsL[NUM_ALLPASS / 3] = {0xD7, 0x6F, 0x36, 0x22};
s32 gReverbMultsR[NUM_ALLPASS / 3] = {0xCF, 0x73, 0x38, 0x1F};
/* -----------------------------------------------------------------------END REVERB PARAMETERS----------------------------------------------------------------------- */
// Do not touch these values manually, unless you want potential for problems.
u8 toggleBetterReverb = TRUE;
static u8 monoReverb = FALSE;
static s32 reverbFilterCount = NUM_ALLPASS;
u8 gBetterReverbPreset = 0;
u8 toggleBetterReverb = FALSE;
u8 monoReverb;
s8 betterReverbDownsampleRate;
static u8 reverbMultsL[NUM_ALLPASS / 3] = {0};
static u8 reverbMultsR[NUM_ALLPASS / 3] = {0};
static s32 allpassIdxL[NUM_ALLPASS] = {0};
static s32 allpassIdxR[NUM_ALLPASS] = {0};
static s32 delaysL[NUM_ALLPASS] = {0};
static s32 delaysR[NUM_ALLPASS] = {0};
static u8 reverbMultsL[NUM_ALLPASS / 3] = {0};
static u8 reverbMultsR[NUM_ALLPASS / 3] = {0};
static s32 **delayBufsL;
static s32 **delayBufsR;
s32 reverbLastFilterIndex;
s32 reverbFilterCount;
s32 betterReverbWindowsSize;
s32 betterReverbRevIndex; // This one is okay to adjust whenever
s32 betterReverbGainIndex; // This one is okay to adjust whenever
s32 *gReverbMultsL;
s32 *gReverbMultsR;
#endif
@@ -203,10 +108,10 @@ static void reverb_samples(s16 *outSampleL, s16 *outSampleR, s32 inSampleL, s32
s32 k = 0;
s32 outTmpL = 0;
s32 outTmpR = 0;
s32 tmpCarryoverL = (((delayBufsL[reverbFilterCount][allpassIdxL[reverbFilterCount]] * REVERB_REV_INDEX) >> 8) + inSampleL);
s32 tmpCarryoverR = (((delayBufsR[reverbFilterCount][allpassIdxR[reverbFilterCount]] * REVERB_REV_INDEX) >> 8) + inSampleR);
s32 tmpCarryoverL = ((delayBufsL[reverbLastFilterIndex][allpassIdxL[reverbLastFilterIndex]] * betterReverbRevIndex) >> 8) + inSampleL;
s32 tmpCarryoverR = ((delayBufsR[reverbLastFilterIndex][allpassIdxR[reverbLastFilterIndex]] * betterReverbRevIndex) >> 8) + inSampleR;
for (; i <= reverbFilterCount; ++i, ++j) {
for (; i <= reverbLastFilterIndex; ++i, ++j) {
curDelaySampleL = &delayBufsL[i][allpassIdxL[i]];
curDelaySampleR = &delayBufsR[i][allpassIdxR[i]];
historySampleL = *curDelaySampleL;
@@ -214,29 +119,27 @@ static void reverb_samples(s16 *outSampleL, s16 *outSampleR, s32 inSampleL, s32
if (j == 2) {
j = -1;
outTmpL += ((historySampleL * reverbMultsL[k ]) >> 8);
outTmpR += ((historySampleR * reverbMultsR[k++]) >> 8);
outTmpL += (historySampleL * reverbMultsL[k ]) >> 8;
outTmpR += (historySampleR * reverbMultsR[k++]) >> 8;
*curDelaySampleL = tmpCarryoverL;
*curDelaySampleR = tmpCarryoverR;
if (i != reverbFilterCount) {
tmpCarryoverL = ((historySampleL * REVERB_REV_INDEX) >> 8);
tmpCarryoverR = ((historySampleR * REVERB_REV_INDEX) >> 8);
if (i != reverbLastFilterIndex) {
tmpCarryoverL = ((historySampleL * betterReverbRevIndex) >> 8)/* + inSampleL*/;
tmpCarryoverR = ((historySampleR * betterReverbRevIndex) >> 8)/* + inSampleR*/;
}
} else {
*curDelaySampleL = (((historySampleL * (-REVERB_GAIN_INDEX)) >> 8) + tmpCarryoverL);
*curDelaySampleR = (((historySampleR * (-REVERB_GAIN_INDEX)) >> 8) + tmpCarryoverR);
tmpCarryoverL = (((*curDelaySampleL * REVERB_GAIN_INDEX) >> 8) + historySampleL);
tmpCarryoverR = (((*curDelaySampleR * REVERB_GAIN_INDEX) >> 8) + historySampleR);
*curDelaySampleL = ((historySampleL * (-betterReverbGainIndex)) >> 8) + tmpCarryoverL;
*curDelaySampleR = ((historySampleR * (-betterReverbGainIndex)) >> 8) + tmpCarryoverR;
tmpCarryoverL = ((*curDelaySampleL * betterReverbGainIndex) >> 8) + historySampleL;
tmpCarryoverR = ((*curDelaySampleR * betterReverbGainIndex) >> 8) + historySampleR;
}
if (++allpassIdxL[i] == delaysL[i]) allpassIdxL[i] = 0;
if (++allpassIdxR[i] == delaysR[i]) allpassIdxR[i] = 0;
}
s32 outUnclamped = ((outTmpL * REVERB_WET_SIGNAL/* + inSampleL * REVERB_DRY_SIGNAL*/) >> 8);
*outSampleL = CLAMP_S16(outUnclamped);
outUnclamped = ((outTmpR * REVERB_WET_SIGNAL/* + inSampleL * REVERB_DRY_SIGNAL*/) >> 8);
*outSampleR = CLAMP_S16(outUnclamped);
*outSampleL = CLAMP_S16(outTmpL);
*outSampleR = CLAMP_S16(outTmpR);
}
static void reverb_mono_sample(s16 *outSample, s32 inSample) {
@@ -246,9 +149,9 @@ static void reverb_mono_sample(s16 *outSample, s32 inSample) {
s32 j = 0;
s32 k = 0;
s32 outTmp = 0;
s32 tmpCarryover = (((delayBufsL[reverbFilterCount][allpassIdxL[reverbFilterCount]] * REVERB_REV_INDEX) >> 8) + inSample);
s32 tmpCarryover = ((delayBufsL[reverbLastFilterIndex][allpassIdxL[reverbLastFilterIndex]] * betterReverbRevIndex) >> 8) + inSample;
for (; i <= reverbFilterCount; ++i, ++j) {
for (; i <= reverbLastFilterIndex; ++i, ++j) {
curDelaySample = &delayBufsL[i][allpassIdxL[i]];
historySample = *curDelaySample;
@@ -256,45 +159,49 @@ static void reverb_mono_sample(s16 *outSample, s32 inSample) {
j = -1;
outTmp += ((historySample * reverbMultsL[k++]) >> 8);
*curDelaySample = tmpCarryover;
if (i != reverbFilterCount)
tmpCarryover = ((historySample * REVERB_REV_INDEX) >> 8);
if (i != reverbLastFilterIndex)
tmpCarryover = ((historySample * betterReverbRevIndex) >> 8)/* + inSample*/;
} else {
*curDelaySample = (((historySample * (-REVERB_GAIN_INDEX)) >> 8) + tmpCarryover);
tmpCarryover = (((*curDelaySample * REVERB_GAIN_INDEX) >> 8) + historySample);
*curDelaySample = ((historySample * (-betterReverbGainIndex)) >> 8) + tmpCarryover;
tmpCarryover = ((*curDelaySample * betterReverbGainIndex) >> 8) + historySample;
}
if (++allpassIdxL[i] == delaysL[i]) allpassIdxL[i] = 0;
}
s32 outUnclamped = ((outTmp * REVERB_WET_SIGNAL/* + inSample * REVERB_DRY_SIGNAL*/) >> 8);
*outSample = CLAMP_S16(outUnclamped);
*outSample = CLAMP_S16(outTmp);
}
void initialize_better_reverb_buffers(void) {
delayBufsL = (s32**) soundAlloc(&gBetterReverbPool, BETTER_REVERB_PTR_SIZE);
delayBufsR = &delayBufsL[NUM_ALLPASS];
delayBufsL[0] = (s32*) soundAlloc(&gBetterReverbPool, BETTER_REVERB_SIZE - BETTER_REVERB_PTR_SIZE);
}
void clear_better_reverb_buffers(void) {
bzero(delayBufsL[0], (BETTER_REVERB_SIZE - BETTER_REVERB_PTR_SIZE));
bzero(allpassIdxL, sizeof(allpassIdxL));
bzero(allpassIdxR, sizeof(allpassIdxR));
}
void set_better_reverb_buffers(void) {
void set_better_reverb_buffers(u32 *inputDelaysL, u32 *inputDelaysR) {
s32 bufOffset = 0;
s32 i;
for (i = 0; i < NUM_ALLPASS; ++i) {
delaysL[i] = (delaysBaselineL[i] / gReverbDownsampleRate);
delaysR[i] = (delaysBaselineR[i] / gReverbDownsampleRate);
delayBufsL[i] = (s32*) &delayBufsL[0][bufOffset];
gBetterReverbPool.cur = gBetterReverbPool.start + ALIGN16(BETTER_REVERB_PTR_SIZE); // Reset reverb data pool
// Don't bother setting any buffers if BETTER_REVERB is disabled
if (!toggleBetterReverb)
return;
// NOTE: Using reverbFilterCount over NUM_ALLPASS will report less memory usage with fewer filters, but poses an additional
// risk to anybody testing on console with performance compromises, as emulator can be easily overlooked.
for (i = 0; i < reverbFilterCount; ++i) {
delaysL[i] = (s32) (inputDelaysL[i] / gReverbDownsampleRate);
delaysR[i] = (s32) (inputDelaysR[i] / gReverbDownsampleRate);
delayBufsL[i] = soundAlloc(&gBetterReverbPool, delaysL[i] * sizeof(s32));
bufOffset += delaysL[i];
delayBufsR[i] = (s32*) &delayBufsL[0][bufOffset]; // L and R buffers are interleaved adjacently in memory; not a bug
delayBufsR[i] = soundAlloc(&gBetterReverbPool, delaysR[i] * sizeof(s32));
bufOffset += delaysR[i];
}
aggress(bufOffset * sizeof(s32) <= BETTER_REVERB_SIZE - ALIGN16(BETTER_REVERB_PTR_SIZE), "BETTER_REVERB_SIZE is too small for this preset!");
bzero(allpassIdxL, sizeof(allpassIdxL));
bzero(allpassIdxR, sizeof(allpassIdxR));
}
#endif
@@ -372,12 +279,12 @@ void prepare_reverb_ring_buffer(s32 chunkLen, u32 updateIndex) {
s32 nSamples;
s32 excessiveSamples;
if (gSynthesisReverb.framesLeftToIgnore == 0) {
#ifdef BETTER_REVERB
if (!toggleBetterReverb && gReverbDownsampleRate != 1) {
if (!toggleBetterReverb && gReverbDownsampleRate != 1) {
#else
if (gReverbDownsampleRate != 1) {
if (gReverbDownsampleRate != 1) {
#endif
if (gSynthesisReverb.framesLeftToIgnore == 0) {
// Now that the RSP has finished, downsample the samples produced two frames ago by skipping
// samples.
item = &gSynthesisReverb.items[gSynthesisReverb.curFrame][updateIndex];
@@ -395,49 +302,47 @@ void prepare_reverb_ring_buffer(s32 chunkLen, u32 updateIndex) {
gSynthesisReverb.ringBuffer.right[dstPos] = item->toDownsampleRight[srcPos];
}
}
}
#ifdef BETTER_REVERB
else if (toggleBetterReverb) {
reverbFilterCount--; // Temporarily lower filter count for optimized bulk processing
item = &gSynthesisReverb.items[gSynthesisReverb.curFrame][updateIndex];
if (gSoundMode == SOUND_MODE_MONO || monoReverb) {
if (gReverbDownsampleRate != 1) {
osInvalDCache(item->toDownsampleLeft, DEFAULT_LEN_2CH);
for (srcPos = 0, dstPos = item->startPos; dstPos < ((item->lengthA / 2) + item->startPos); srcPos += gReverbDownsampleRate, dstPos++) {
reverb_mono_sample(&gSynthesisReverb.ringBuffer.left[dstPos], ((s32) item->toDownsampleLeft[srcPos] + (s32) item->toDownsampleRight[srcPos]) / 2);
gSynthesisReverb.ringBuffer.right[dstPos] = gSynthesisReverb.ringBuffer.left[dstPos];
}
for (dstPos = 0; dstPos < (item->lengthB / 2); srcPos += gReverbDownsampleRate, dstPos++) {
reverb_mono_sample(&gSynthesisReverb.ringBuffer.left[dstPos], ((s32) item->toDownsampleLeft[srcPos] + (s32) item->toDownsampleRight[srcPos]) / 2);
gSynthesisReverb.ringBuffer.right[dstPos] = gSynthesisReverb.ringBuffer.left[dstPos];
else if (toggleBetterReverb) {
item = &gSynthesisReverb.items[gSynthesisReverb.curFrame][updateIndex];
if (gSoundMode == SOUND_MODE_MONO || monoReverb) {
if (gReverbDownsampleRate != 1) {
osInvalDCache(item->toDownsampleLeft, DEFAULT_LEN_2CH);
for (srcPos = 0, dstPos = item->startPos; dstPos < ((item->lengthA / 2) + item->startPos); srcPos += gReverbDownsampleRate, dstPos++) {
reverb_mono_sample(&gSynthesisReverb.ringBuffer.left[dstPos], ((s32) item->toDownsampleLeft[srcPos] + (s32) item->toDownsampleRight[srcPos]) / 2);
gSynthesisReverb.ringBuffer.right[dstPos] = gSynthesisReverb.ringBuffer.left[dstPos];
}
for (dstPos = 0; dstPos < (item->lengthB / 2); srcPos += gReverbDownsampleRate, dstPos++) {
reverb_mono_sample(&gSynthesisReverb.ringBuffer.left[dstPos], ((s32) item->toDownsampleLeft[srcPos] + (s32) item->toDownsampleRight[srcPos]) / 2);
gSynthesisReverb.ringBuffer.right[dstPos] = gSynthesisReverb.ringBuffer.left[dstPos];
}
} else {
for (dstPos = item->startPos; dstPos < ((item->lengthA / 2) + item->startPos); dstPos++) {
reverb_mono_sample(&gSynthesisReverb.ringBuffer.left[dstPos], ((s32) gSynthesisReverb.ringBuffer.left[dstPos] + (s32) gSynthesisReverb.ringBuffer.right[dstPos]) / 2);
gSynthesisReverb.ringBuffer.right[dstPos] = gSynthesisReverb.ringBuffer.left[dstPos];
}
for (dstPos = 0; dstPos < (item->lengthB / 2); dstPos++) {
reverb_mono_sample(&gSynthesisReverb.ringBuffer.left[dstPos], ((s32) gSynthesisReverb.ringBuffer.left[dstPos] + (s32) gSynthesisReverb.ringBuffer.right[dstPos]) / 2);
gSynthesisReverb.ringBuffer.right[dstPos] = gSynthesisReverb.ringBuffer.left[dstPos];
}
}
} else {
for (dstPos = item->startPos; dstPos < ((item->lengthA / 2) + item->startPos); dstPos++) {
reverb_mono_sample(&gSynthesisReverb.ringBuffer.left[dstPos], ((s32) gSynthesisReverb.ringBuffer.left[dstPos] + (s32) gSynthesisReverb.ringBuffer.right[dstPos]) / 2);
gSynthesisReverb.ringBuffer.right[dstPos] = gSynthesisReverb.ringBuffer.left[dstPos];
if (gReverbDownsampleRate != 1) {
osInvalDCache(item->toDownsampleLeft, DEFAULT_LEN_2CH);
for (srcPos = 0, dstPos = item->startPos; dstPos < ((item->lengthA / 2) + item->startPos); srcPos += gReverbDownsampleRate, dstPos++)
reverb_samples(&gSynthesisReverb.ringBuffer.left[dstPos], &gSynthesisReverb.ringBuffer.right[dstPos], item->toDownsampleLeft[srcPos], item->toDownsampleRight[srcPos]);
for (dstPos = 0; dstPos < (item->lengthB / 2); srcPos += gReverbDownsampleRate, dstPos++)
reverb_samples(&gSynthesisReverb.ringBuffer.left[dstPos], &gSynthesisReverb.ringBuffer.right[dstPos], item->toDownsampleLeft[srcPos], item->toDownsampleRight[srcPos]);
} else {
for (dstPos = item->startPos; dstPos < ((item->lengthA / 2) + item->startPos); dstPos++)
reverb_samples(&gSynthesisReverb.ringBuffer.left[dstPos], &gSynthesisReverb.ringBuffer.right[dstPos], gSynthesisReverb.ringBuffer.left[dstPos], gSynthesisReverb.ringBuffer.right[dstPos]);
for (dstPos = 0; dstPos < (item->lengthB / 2); dstPos++)
reverb_samples(&gSynthesisReverb.ringBuffer.left[dstPos], &gSynthesisReverb.ringBuffer.right[dstPos], gSynthesisReverb.ringBuffer.left[dstPos], gSynthesisReverb.ringBuffer.right[dstPos]);
}
for (dstPos = 0; dstPos < (item->lengthB / 2); dstPos++) {
reverb_mono_sample(&gSynthesisReverb.ringBuffer.left[dstPos], ((s32) gSynthesisReverb.ringBuffer.left[dstPos] + (s32) gSynthesisReverb.ringBuffer.right[dstPos]) / 2);
gSynthesisReverb.ringBuffer.right[dstPos] = gSynthesisReverb.ringBuffer.left[dstPos];
}
}
} else {
if (gReverbDownsampleRate != 1) {
osInvalDCache(item->toDownsampleLeft, DEFAULT_LEN_2CH);
for (srcPos = 0, dstPos = item->startPos; dstPos < ((item->lengthA / 2) + item->startPos); srcPos += gReverbDownsampleRate, dstPos++)
reverb_samples(&gSynthesisReverb.ringBuffer.left[dstPos], &gSynthesisReverb.ringBuffer.right[dstPos], item->toDownsampleLeft[srcPos], item->toDownsampleRight[srcPos]);
for (dstPos = 0; dstPos < (item->lengthB / 2); srcPos += gReverbDownsampleRate, dstPos++)
reverb_samples(&gSynthesisReverb.ringBuffer.left[dstPos], &gSynthesisReverb.ringBuffer.right[dstPos], item->toDownsampleLeft[srcPos], item->toDownsampleRight[srcPos]);
} else {
for (dstPos = item->startPos; dstPos < ((item->lengthA / 2) + item->startPos); dstPos++)
reverb_samples(&gSynthesisReverb.ringBuffer.left[dstPos], &gSynthesisReverb.ringBuffer.right[dstPos], gSynthesisReverb.ringBuffer.left[dstPos], gSynthesisReverb.ringBuffer.right[dstPos]);
for (dstPos = 0; dstPos < (item->lengthB / 2); dstPos++)
reverb_samples(&gSynthesisReverb.ringBuffer.left[dstPos], &gSynthesisReverb.ringBuffer.right[dstPos], gSynthesisReverb.ringBuffer.left[dstPos], gSynthesisReverb.ringBuffer.right[dstPos]);
}
}
reverbFilterCount++; // Reset filter count to accurate numbers
}
#endif
}
item = &gSynthesisReverb.items[gSynthesisReverb.curFrame][updateIndex];
s32 numSamplesAfterDownsampling = chunkLen / gReverbDownsampleRate;
@@ -564,7 +469,7 @@ u64 *synthesis_execute(u64 *cmdBuf, s32 *writtenCmds, s16 *aiBuf, s32 bufLen) {
gCurrentLeftVolRamping = leftVolRamp;
gCurrentRightVolRamping = rightVolRamp;
for (j = 0; j < gNumSynthesisReverbs; j++) {
if (gSynthesisReverbs[j].useReverb != 0) {
if (gSynthesisReverbs[j].useReverb) {
prepare_reverb_ring_buffer(chunkLen, gAudioBufferParameters.updatesPerFrame - i, j);
}
}
@@ -594,26 +499,23 @@ u64 *synthesis_execute(u64 *cmdBuf, s32 *writtenCmds, s16 *aiBuf, s32 bufLen) {
aSegment(cmdBuf, 0, 0);
#ifdef BETTER_REVERB
if (gIsConsole) {
reverbFilterCount = reverbFilterCountConsole;
monoReverb = monoReverbConsole;
} else {
reverbFilterCount = reverbFilterCountEmulator;
monoReverb = monoReverbEmulator;
}
s32 filterCountDiv3 = reverbFilterCount / 3;
reverbFilterCount = filterCountDiv3 * 3; // reverbFilterCount should always be a multiple of 3.
if (reverbFilterCount > NUM_ALLPASS) {
reverbFilterCount = NUM_ALLPASS;
} else if (reverbFilterCount < 3) {
reverbFilterCount = 3;
}
s32 filterCountDiv3 = reverbFilterCount / 3;
reverbFilterCount = filterCountDiv3 * 3; // reverbFilterCount should always be a multiple of 3.
reverbLastFilterIndex = reverbFilterCount - 1;
// Update reverbMultsL every audio frame just in case gReverbMults is ever to change.
for (i = 0; i < filterCountDiv3; ++i) {
reverbMultsL[i] = gReverbMultsL[i];
reverbMultsR[i] = gReverbMultsR[i];
if (gReverbMultsL != NULL && gReverbMultsR != NULL) {
for (i = 0; i < filterCountDiv3; ++i) {
reverbMultsL[i] = gReverbMultsL[i];
reverbMultsR[i] = gReverbMultsR[i];
}
}
// If there's only one reverb multiplier set, adjust these to match so one channel doesn't end up potentially overpowering the other.
@@ -637,7 +539,7 @@ u64 *synthesis_execute(u64 *cmdBuf, s32 *writtenCmds, s16 *aiBuf, s32 bufLen) {
}
}
process_sequences(i - 1);
if (gSynthesisReverb.useReverb != 0) {
if (gSynthesisReverb.useReverb) {
prepare_reverb_ring_buffer(chunkLen, gAudioUpdatesPerFrame - i);
}
cmd = synthesis_do_one_audio_update((s16 *) aiBufPtr, chunkLen, cmd, gAudioUpdatesPerFrame - i);
@@ -697,7 +599,7 @@ u64 *synthesis_save_reverb_samples(u64 *cmd, s16 reverbIndex, s16 updateIndex) {
struct ReverbRingBufferItem *item;
item = &gSynthesisReverbs[reverbIndex].items[gSynthesisReverbs[reverbIndex].curFrame][updateIndex];
if (gSynthesisReverbs[reverbIndex].useReverb != 0) {
if (gSynthesisReverbs[reverbIndex].useReverb) {
switch (gSynthesisReverbs[reverbIndex].downsampleRate) {
case 1:
// Put the oldest samples in the ring buffer into the wet channels
@@ -757,7 +659,7 @@ u64 *synthesis_do_one_audio_update(s16 *aiBuf, s32 bufLen, u64 *cmd, s32 updateI
i = 0;
for (j = 0; j < gNumSynthesisReverbs; j++) {
gUseReverb = gSynthesisReverbs[j].useReverb;
if (gUseReverb != 0) {
if (gUseReverb) {
cmd = synthesis_resample_and_mix_reverb(cmd, bufLen, j, updateIndex);
}
for (; i < notePos; i++) {
@@ -772,7 +674,7 @@ u64 *synthesis_do_one_audio_update(s16 *aiBuf, s32 bufLen, u64 *cmd, s32 updateI
break;
}
}
if (gSynthesisReverbs[j].useReverb != 0) {
if (gSynthesisReverbs[j].useReverb) {
cmd = synthesis_save_reverb_samples(cmd, j, updateIndex);
}
}
@@ -803,7 +705,7 @@ u64 *synthesis_do_one_audio_update(s16 *aiBuf, s32 bufLen, u64 *cmd, s32 updateI
v1 = &gSynthesisReverb.items[gSynthesisReverb.curFrame][updateIndex];
if (gSynthesisReverb.useReverb == 0) {
if (!gSynthesisReverb.useReverb) {
aClearBuffer(cmd++, DMEM_ADDR_LEFT_CH, DEFAULT_LEN_2CH);
cmd = synthesis_process_notes(aiBuf, bufLen, cmd);
} else {

View File

@@ -21,28 +21,22 @@
#ifdef BETTER_REVERB
#define NUM_ALLPASS 12 // Number of delay filters to use with better reverb; do not change this value if you don't know what you're doing.
#define NUM_ALLPASS 12 // Maximum number of delay filters to use with better reverb; do not change this value if you don't know what you're doing.
#define BETTER_REVERB_PTR_SIZE ALIGN16(NUM_ALLPASS * sizeof(s32*) * 2) // Allocation space consumed by dynamically allocated pointers
// Size determined by (all delaysBaselineL/R values * 8) / (2 ^ Minimum Downsample Factor).
// The default value can be increased or decreased in conjunction with the values in delaysBaselineL/R
#define BETTER_REVERB_SIZE ALIGN16(0xF200 + BETTER_REVERB_PTR_SIZE)
// Size determined by (all delaysL/R values * 8) / (2 ^ Minimum Downsample Factor).
// The default value can be increased or decreased in conjunction with the values in delaysL/R
#define BETTER_REVERB_SIZE ALIGN16(0x1E000 + BETTER_REVERB_PTR_SIZE) // This can be significantly decreased if a downsample rate of 1 is not being used.
// #define BETTER_REVERB_SIZE (0x7A00 + BETTER_REVERB_PTR_SIZE) // Default for use only with a downsampling value of 3 (i.e. double the emulator default)
// #define BETTER_REVERB_SIZE (0x1E200 + BETTER_REVERB_PTR_SIZE) // Default for use with a downsampling value of 1 (i.e. no downsampling at all)
extern s8 betterReverbDownsampleConsole;
extern s8 betterReverbDownsampleEmulator;
extern u8 monoReverbConsole;
extern u8 monoReverbEmulator;
extern s32 reverbFilterCountConsole;
extern s32 reverbFilterCountEmulator;
extern u8 gBetterReverbPreset;
extern s8 betterReverbDownsampleRate;
extern u8 monoReverb;
extern s32 reverbFilterCount;
extern s32 betterReverbWindowsSize;
extern s32 delaysBaselineL[NUM_ALLPASS];
extern s32 delaysBaselineR[NUM_ALLPASS];
extern s32 gReverbMultsL[NUM_ALLPASS / 3];
extern s32 gReverbMultsR[NUM_ALLPASS / 3];
extern s32 betterReverbRevIndex;
extern s32 betterReverbGainIndex;
extern s32 *gReverbMultsL;
extern s32 *gReverbMultsR;
extern u8 toggleBetterReverb;
#define REVERB_WINDOW_SIZE_MAX 0x2000
@@ -147,8 +141,7 @@ extern s16 D_SH_803479B4;
#ifdef BETTER_REVERB
void initialize_better_reverb_buffers(void);
void clear_better_reverb_buffers(void);
void set_better_reverb_buffers(void);
void set_better_reverb_buffers(u32 *inputDelaysL, u32 *inputDelaysR);
#endif
u64 *synthesis_execute(u64 *cmdBuf, s32 *writtenCmds, s16 *aiBuf, s32 bufLen);

View File

@@ -177,7 +177,7 @@ u64 *synthesis_execute(u64 *cmdBuf, s32 *writtenCmds, s16 *aiBuf, s32 bufLen) {
}
}
for (j = 0; j < gNumSynthesisReverbs; j++) {
if (gSynthesisReverbs[j].useReverb != 0) {
if (gSynthesisReverbs[j].useReverb) {
prepare_reverb_ring_buffer(chunkLen, gAudioBufferParameters.updatesPerFrame - i, j);
}
}
@@ -319,7 +319,7 @@ u64 *synthesis_do_one_audio_update(s16 *aiBuf, s32 bufLen, u64 *cmd, s32 updateI
i = 0;
for (j = 0; j < gNumSynthesisReverbs; j++) {
gUseReverb = gSynthesisReverbs[j].useReverb;
if (gUseReverb != 0) {
if (gUseReverb) {
cmd = synthesis_resample_and_mix_reverb(cmd, bufLen, j, updateIndex);
}
for (; i < notePos; i++) {
@@ -334,7 +334,7 @@ u64 *synthesis_do_one_audio_update(s16 *aiBuf, s32 bufLen, u64 *cmd, s32 updateI
break;
}
}
if (gSynthesisReverbs[j].useReverb != 0) {
if (gSynthesisReverbs[j].useReverb) {
if (gSynthesisReverbs[j].unk100 != NULL) {
aFilter(cmd++, 0x02, bufLen * 2, gSynthesisReverbs[j].unk100);
aFilter(cmd++, gSynthesisReverbs[j].resampleFlags, DMEM_ADDR_WET_LEFT_CH, gSynthesisReverbs[j].unk108);

View File

@@ -5,6 +5,7 @@
#include "sm64.h"
#include "audio/external.h"
#include "audio/synthesis.h"
#include "buffers/framebuffers.h"
#include "buffers/zbuffer.h"
#include "game/area.h"
@@ -735,18 +736,43 @@ static void level_cmd_show_dialog(void) {
static void level_cmd_set_music(void) {
if (sCurrAreaIndex != -1) {
gAreas[sCurrAreaIndex].musicParam = CMD_GET(s16, 2);
gAreas[sCurrAreaIndex].musicParam2 = CMD_GET(s16, 4);
#ifdef BETTER_REVERB
if (gIsConsole)
gAreas[sCurrAreaIndex].betterReverbPreset = CMD_GET(u8, 4);
else
gAreas[sCurrAreaIndex].betterReverbPreset = CMD_GET(u8, 5);
#endif
gAreas[sCurrAreaIndex].musicParam2 = CMD_GET(s16, 6);
}
sCurrentCmd = CMD_NEXT;
}
static void level_cmd_set_menu_music(void) {
#ifdef BETTER_REVERB
// Must come before set_background_music()
if (gIsConsole)
gBetterReverbPreset = CMD_GET(u8, 4);
else
gBetterReverbPreset = CMD_GET(u8, 5);
#endif
set_background_music(0, CMD_GET(s16, 2), 0);
sCurrentCmd = CMD_NEXT;
}
static void level_cmd_fadeout_music(void) {
fadeout_music(CMD_GET(s16, 2));
s16 dur = CMD_GET(s16, 2);
if (sCurrAreaIndex != -1 && dur == 0) {
// Allow persistent block overrides for SET_BACKGROUND_MUSIC_WITH_REVERB
gAreas[sCurrAreaIndex].musicParam = 0x00;
gAreas[sCurrAreaIndex].musicParam2 = 0x00;
#ifdef BETTER_REVERB
gAreas[sCurrAreaIndex].betterReverbPreset = 0x00;
#endif
} else {
if (dur < 0)
dur = 0;
fadeout_music(dur);
}
sCurrentCmd = CMD_NEXT;
}

View File

@@ -205,6 +205,9 @@ void clear_areas(void) {
gAreaData[i].dialog[1] = DIALOG_NONE;
gAreaData[i].musicParam = 0;
gAreaData[i].musicParam2 = 0;
#ifdef BETTER_REVERB
gAreaData[i].betterReverbPreset = 0;
#endif
}
}

Some files were not shown because too many files have changed in this diff Show More