diff --git a/src/audio/heap.c b/src/audio/heap.c index 27423a10..d7580eed 100644 --- a/src/audio/heap.c +++ b/src/audio/heap.c @@ -1240,9 +1240,9 @@ void audio_reset_session(void) { gReverbDownsampleRate = preset->reverbDownsampleRate; #ifdef BETTER_REVERB if (gIsConsole) - reverbConsole = betterReverbConsoleDownsample; // Console! + reverbConsole = betterReverbDownsampleConsole; // Console! else - reverbConsole = betterReverbEmulatorDownsample; // Setting this to 1 is REALLY slow, please use sparingly! + reverbConsole = betterReverbDownsampleEmulator; // Setting this to 1 is REALLY slow, please use sparingly! if (reverbConsole <= 0) { reverbConsole = 1; @@ -1457,15 +1457,16 @@ void audio_reset_session(void) { // 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) { - for (i = 0; i < NUM_ALLPASS; ++i) - delays[i] = delaysBaseline[i] / gReverbDownsampleRate; - - delayBufs = (s32***) soundAlloc(&gAudioSessionPool, 2 * sizeof(s32**)); - delayBufs[0] = (s32**) soundAlloc(&gAudioSessionPool, NUM_ALLPASS * sizeof(s32*)); - delayBufs[1] = (s32**) soundAlloc(&gAudioSessionPool, NUM_ALLPASS * sizeof(s32*)); for (i = 0; i < NUM_ALLPASS; ++i) { - delayBufs[0][i] = (s32*) soundAlloc(&gAudioSessionPool, delays[i] * sizeof(s32)); - delayBufs[1][i] = (s32*) soundAlloc(&gAudioSessionPool, delays[i] * sizeof(s32)); + delaysL[i] = delaysBaselineL[i] / gReverbDownsampleRate; + delaysR[i] = delaysBaselineR[i] / gReverbDownsampleRate; + } + + delayBufsL = (s32**) soundAlloc(&gAudioSessionPool, NUM_ALLPASS * sizeof(s32*)); + delayBufsR = (s32**) soundAlloc(&gAudioSessionPool, NUM_ALLPASS * sizeof(s32*)); + for (i = 0; i < NUM_ALLPASS; ++i) { + delayBufsL[i] = (s32*) soundAlloc(&gAudioSessionPool, delaysL[i] * sizeof(s32)); + delayBufsR[i] = (s32*) soundAlloc(&gAudioSessionPool, delaysR[i] * sizeof(s32)); } } #endif diff --git a/src/audio/synthesis.c b/src/audio/synthesis.c index 347efc87..38f242f1 100644 --- a/src/audio/synthesis.c +++ b/src/audio/synthesis.c @@ -8,6 +8,7 @@ #include "seqplayer.h" #include "internal.h" #include "external.h" +#include "game/game_init.h" #define DMEM_ADDR_TEMP 0x0 @@ -37,6 +38,7 @@ #define AUDIO_ALIGN(val, amnt) (((val) + (1 << amnt) - 1) & ~((1 << amnt) - 1)) +#ifdef BETTER_REVERB /* ----------------------------------------------------------------------BEGIN REVERB PARAMETERS---------------------------------------------------------------------- */ @@ -47,6 +49,13 @@ * 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. + * Checks to prevent this have not been implemented to maximize performance potential, so choose your parameters wisely. + * Generally speaking, a sound that doesn't seem to be fading is a parameter red flag (also known as feedback). */ @@ -54,19 +63,36 @@ // 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 level issue (and also counter intuitive). // Higher downsample values also result in slightly shorter reverb decay times. -s8 betterReverbConsoleDownsample = 3; +s8 betterReverbDownsampleConsole = 3; // Most emulators can handle a default value of 2, but 3 may be advisable in some cases if targeting older emulators (e.g. PJ64 1.6). Setting this to -1 also uses vanilla reverb. // Using a value of 1 is not recommended except in very specific situations. 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 level issue (and also counter intuitive). // Higher downsample values also result in slightly shorter reverb decay times. -s8 betterReverbEmulatorDownsample = 2; +s8 betterReverbDownsampleEmulator = 2; -s32 gReverbRevIndex = 0x5F; // Affects decay time mostly (large values can cause terrible feedback!); can be messed with at any time -s32 gReverbGainIndex = 0x9F; // Affects signal immediately retransmitted back into buffers (mid-high values yield the strongest effect); can be messed with at any time -s32 gReverbWetSignal = 0xE7; // Amount of reverb specific output in final signal (also affects decay); can be messed with at any time, also very easy to control -s32 gReverbDrySignal = 0x00; // Amount of original input in final signal (large values can cause terrible feedback!); can be messed with at any time +// 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. +// Setting it to anything less 3 will disable reverb outright. +// This can be changed at any time, but is best set when calling audio_reset_session. +u32 reverbFilterCountConsole = NUM_ALLPASS - 3; + +// 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. +// Setting it to anything less 3 will disable reverb outright. +// This can be changed at any time, but is best set when calling audio_reset_session. +u32 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 fullfilling 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 when 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 fullfilling 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 when 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. // It is not recommended setting this to values greater than 0x1000 * 2^(downsample factor - 1), as you run the risk of running into a memory issue (though this is far from a guarantee). @@ -75,50 +101,69 @@ s32 gReverbDrySignal = 0x00; // Amount of original input in final signal (large // Set to -1 to use a default preset instead. Higher values represent more audio delay (usually better for echoey spaces). s32 betterReverbWindowsSize = -1; +s32 gReverbRevIndex = 0x5F; // Affects decay time mostly (large values can cause terrible feedback!); can be messed with at any time +s32 gReverbGainIndex = 0x9F; // Affects signal immediately retransmitted back into buffers (mid-high values yield the strongest effect); can be messed with at any time +s32 gReverbWetSignal = 0xE7; // Amount of reverb specific output in final signal (also affects decay); can be messed with at any time, also very easy to control + +// s32 gReverbDrySignal = 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/4. -// If setting a reverb downsample value to 1, this must be smaller than BETTER_REVERB_SIZE/8. +// 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. // These values should never be changed unless in this declaration or during a call to audio_reset_session, as it could otherwise lead to a major memory leak or garbage audio. // None of the delay values should ever be smaller than 1 either; these are s32s purely to avoid typecasts. // These values are currently set by using delaysBaseline in the audio_reset_session function, so its behavior must be overridden to use dynamically (or at all). -s32 delays[NUM_ALLPASS] = { +s32 delaysL[NUM_ALLPASS] = { 1080, 1352, 1200, - 1384, 1048, 1352, 1200, 1232, 1432, + 1384, 1048, 1352, 928, 1504, 1512 }; +s32 delaysR[NUM_ALLPASS] = { + 1384, 1352, 1048, + 928, 1512, 1504, + 1080, 1200, 1352, + 1200, 1432, 1232 +}; // Like the delays array, but represents default max values that don't change (also probably somewhat redundant) // Change this array rather than the delays array to customize reverb delay times globally. -// Similarly to delays, these should be kept within the memory constraints defined by BETTER_REVERB_SIZE. -const s32 delaysBaseline[NUM_ALLPASS] = { +// Similarly to delaysL/R, these should be kept within the memory constraints defined by BETTER_REVERB_SIZE. +const s32 delaysBaselineL[NUM_ALLPASS] = { 1080, 1352, 1200, - 1384, 1048, 1352, 1200, 1232, 1432, + 1384, 1048, 1352, 928, 1504, 1512 }; +const 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 -const s32 reverbMults[2][NUM_ALLPASS / 3] = { - {0xD2, 0x6E, 0x36, 0x1F}, // Left Channel - {0x38, 0x26, 0xCF, 0x71} // Right Channel -}; +s32 reverbMultsL[NUM_ALLPASS / 3] = {0xD7, 0x6F, 0x36, 0x22}; +s32 reverbMultsR[NUM_ALLPASS / 3] = {0xCF, 0x73, 0x38, 0x1F}; /* -----------------------------------------------------------------------END REVERB PARAMETERS----------------------------------------------------------------------- */ -// Do not touch these values. +// Do not touch these values manually, unless you want potential for problems. +u32 reverbFilterCount = NUM_ALLPASS; +u32 reverbFilterCountm1 = NUM_ALLPASS - 1; +u8 monoReverb = FALSE; u8 toggleBetterReverb = TRUE; -s32 allpassIdx[2][NUM_ALLPASS] = { - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} -}; +s32 allpassIdxL[NUM_ALLPASS] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +s32 allpassIdxR[NUM_ALLPASS] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; s32 tmpBufL[NUM_ALLPASS] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; s32 tmpBufR[NUM_ALLPASS] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; -s32 ***delayBufs; +s32 **delayBufsL; +s32 **delayBufsR; +#endif struct VolumeChange { @@ -154,7 +199,8 @@ struct SynthesisReverb gSynthesisReverb; u8 sAudioSynthesisPad[0x20]; #endif -inline s16 clamp16(s32 x) { +#ifdef BETTER_REVERB +static inline s16 clamp16(s32 x) { if (x >= 32767) return 32767; if (x <= -32768) @@ -163,113 +209,76 @@ inline s16 clamp16(s32 x) { return (s16) x; } -inline void reverb_samples(s16 *outSampleL, s16 *outSampleR, s32 inSampleL, s32 inSampleR) { +static inline void reverb_samples(s16 *outSampleL, s16 *outSampleR, s32 inSampleL, s32 inSampleR) { u32 i = 0; s32 j = 0; u8 k = 0; s32 outTmpL = 0; s32 outTmpR = 0; - s32 tmpCarryoverL = ((tmpBufL[NUM_ALLPASS-1] * gReverbRevIndex) / 256) + inSampleL; // Unique to left channel - s32 tmpCarryoverR = ((tmpBufR[NUM_ALLPASS-1] * gReverbRevIndex) / 256); + s32 tmpCarryoverL = ((tmpBufL[reverbFilterCountm1] * gReverbRevIndex) / 256) + inSampleL; + s32 tmpCarryoverR = ((tmpBufR[reverbFilterCountm1] * gReverbRevIndex) / 256) + inSampleR; - for (; i < NUM_ALLPASS; ++i, ++j) { - tmpBufL[i] = delayBufs[0][i][allpassIdx[0][i]]; - tmpBufR[i] = delayBufs[1][i][allpassIdx[1][i]]; + for (; i < reverbFilterCount; ++i, ++j) { + tmpBufL[i] = delayBufsL[i][allpassIdxL[i]]; + tmpBufR[i] = delayBufsR[i][allpassIdxR[i]]; if (j == 2) { j = -1; - outTmpL += (tmpBufL[i] * reverbMults[0][k]) / 256; - outTmpR += (tmpBufR[i] * reverbMults[1][k++]) / 256; - delayBufs[0][i][allpassIdx[0][i]] = tmpCarryoverL; - delayBufs[1][i][allpassIdx[1][i]] = tmpCarryoverR; - if (i != NUM_ALLPASS - 1) { + outTmpL += (tmpBufL[i] * reverbMultsL[k]) / 256; + outTmpR += (tmpBufR[i] * reverbMultsR[k++]) / 256; + delayBufsL[i][allpassIdxL[i]] = tmpCarryoverL; + delayBufsR[i][allpassIdxR[i]] = tmpCarryoverR; + if (i != reverbFilterCountm1) { tmpCarryoverL = (tmpBufL[i] * gReverbRevIndex) / 256; tmpCarryoverR = (tmpBufR[i] * gReverbRevIndex) / 256; } } else { - delayBufs[0][i][allpassIdx[0][i]] = (tmpBufL[i] * (-gReverbGainIndex)) / 256 + tmpCarryoverL; - delayBufs[1][i][allpassIdx[1][i]] = (tmpBufR[i] * (-gReverbGainIndex)) / 256 + tmpCarryoverR; - - if (i == 6) - delayBufs[1][i][allpassIdx[1][i]] += inSampleR; // Unique to right channel - - tmpCarryoverL = (delayBufs[0][i][allpassIdx[0][i]] * gReverbGainIndex) / 256 + tmpBufL[i]; - tmpCarryoverR = (delayBufs[1][i][allpassIdx[1][i]] * gReverbGainIndex) / 256 + tmpBufR[i]; + delayBufsL[i][allpassIdxL[i]] = (tmpBufL[i] * (-gReverbGainIndex)) / 256 + tmpCarryoverL; + delayBufsR[i][allpassIdxR[i]] = (tmpBufR[i] * (-gReverbGainIndex)) / 256 + tmpCarryoverR; + tmpCarryoverL = (delayBufsL[i][allpassIdxL[i]] * gReverbGainIndex) / 256 + tmpBufL[i]; + tmpCarryoverR = (delayBufsR[i][allpassIdxR[i]] * gReverbGainIndex) / 256 + tmpBufR[i]; } - if (++allpassIdx[0][i] == delays[i]) { - allpassIdx[0][i] = 0; - allpassIdx[1][i] = -1; // To avoid an else branch - } - ++allpassIdx[1][i]; + if (++allpassIdxL[i] == delaysL[i]) + allpassIdxL[i] = 0; + if (++allpassIdxR[i] == delaysR[i]) + allpassIdxR[i] = 0; } - *outSampleL = clamp16((outTmpL * gReverbWetSignal + inSampleL * gReverbDrySignal) / 256); - *outSampleR = clamp16((outTmpR * gReverbWetSignal + inSampleR * gReverbDrySignal) / 256); + *outSampleL = clamp16((outTmpL * gReverbWetSignal/* + inSampleL * gReverbDrySignal*/) / 256); + *outSampleR = clamp16((outTmpR * gReverbWetSignal/* + inSampleR * gReverbDrySignal*/) / 256); } -inline s16 reverb_sample_left(s32 inSample) { +static inline void reverb_mono_sample(s16 *outSample, s32 inSample) { u32 i = 0; s32 j = 0; u8 k = 0; s32 outTmp = 0; - s32 tmpCarryover = ((tmpBufL[NUM_ALLPASS-1] * gReverbRevIndex) / 256) + inSample; + s32 tmpCarryover = ((tmpBufL[reverbFilterCountm1] * gReverbRevIndex) / 256) + inSample; - for (; i < NUM_ALLPASS; ++i, ++j) { - tmpBufL[i] = delayBufs[0][i][allpassIdx[0][i]]; + for (; i < reverbFilterCount; ++i, ++j) { + tmpBufL[i] = delayBufsL[i][allpassIdxL[i]]; if (j == 2) { j = -1; - outTmp += (tmpBufL[i] * reverbMults[0][k++]) / 256; - delayBufs[0][i][allpassIdx[0][i]] = tmpCarryover; - if (i != NUM_ALLPASS - 1) + outTmp += (tmpBufL[i] * reverbMultsL[k++]) / 256; + delayBufsL[i][allpassIdxL[i]] = tmpCarryover; + if (i != reverbFilterCountm1) tmpCarryover = (tmpBufL[i] * gReverbRevIndex) / 256; } else { - delayBufs[0][i][allpassIdx[0][i]] = (tmpBufL[i] * (-gReverbGainIndex)) / 256 + tmpCarryover; - tmpCarryover = (delayBufs[0][i][allpassIdx[0][i]] * gReverbGainIndex) / 256 + tmpBufL[i]; + delayBufsL[i][allpassIdxL[i]] = (tmpBufL[i] * (-gReverbGainIndex)) / 256 + tmpCarryover; + tmpCarryover = (delayBufsL[i][allpassIdxL[i]] * gReverbGainIndex) / 256 + tmpBufL[i]; } - if (++allpassIdx[0][i] == delays[i]) - allpassIdx[0][i] = 0; + if (++allpassIdxL[i] == delaysL[i]) + allpassIdxL[i] = 0; } - return clamp16((outTmp * gReverbWetSignal + inSample * gReverbDrySignal) / 256); -} - -inline s16 reverb_sample_right(s32 inSample) { - u32 i = 0; - s32 j = 0; - u8 k = 0; - s32 outTmp = 0; - s32 tmpCarryover = ((tmpBufR[NUM_ALLPASS-1] * gReverbRevIndex) / 256); - - for (; i < NUM_ALLPASS; ++i, ++j) { - tmpBufR[i] = delayBufs[1][i][allpassIdx[1][i]]; - - if (j == 2) { - j = -1; - outTmp += (tmpBufR[i] * reverbMults[1][k++]) / 256; - delayBufs[1][i][allpassIdx[1][i]] = tmpCarryover; - if (i != NUM_ALLPASS - 1) - tmpCarryover = (tmpBufR[i] * gReverbRevIndex) / 256; - } - else { - delayBufs[1][i][allpassIdx[1][i]] = (tmpBufR[i] * (-gReverbGainIndex)) / 256 + tmpCarryover; - - if (i == 6) - delayBufs[1][i][allpassIdx[1][i]] += inSample; - - tmpCarryover = (delayBufs[1][i][allpassIdx[1][i]] * gReverbGainIndex) / 256 + tmpBufR[i]; - } - - if (++allpassIdx[1][i] == delays[i]) - allpassIdx[1][i] = 0; - } - - return clamp16((outTmp * gReverbWetSignal + inSample * gReverbDrySignal) / 256); + *outSample = clamp16((outTmp * gReverbWetSignal/* + inSample * gReverbDrySignal*/) / 256); } +#endif #ifdef VERSION_EU s16 gVolume; @@ -380,25 +389,25 @@ void prepare_reverb_ring_buffer(s32 chunkLen, u32 updateIndex) { #ifdef BETTER_REVERB else if (toggleBetterReverb) { item = &gSynthesisReverb.items[gSynthesisReverb.curFrame][updateIndex]; - if (gSoundMode == SOUND_MODE_MONO) { + 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++) { - gSynthesisReverb.ringBuffer.left[dstPos] = reverb_sample_left(((s32) item->toDownsampleLeft[srcPos] + (s32) item->toDownsampleRight[srcPos]) / 2); + 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++) { - gSynthesisReverb.ringBuffer.left[dstPos] = reverb_sample_left(((s32) item->toDownsampleLeft[srcPos] + (s32) item->toDownsampleRight[srcPos]) / 2); + 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 { // Too slow for practical use, not recommended most of the time. for (dstPos = item->startPos; dstPos < item->lengthA / 2 + item->startPos; dstPos++) { - gSynthesisReverb.ringBuffer.left[dstPos] = reverb_sample_left(((s32) gSynthesisReverb.ringBuffer.left[dstPos] + (s32) gSynthesisReverb.ringBuffer.right[dstPos]) / 2); + 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++) { - gSynthesisReverb.ringBuffer.left[dstPos] = reverb_sample_left(((s32) gSynthesisReverb.ringBuffer.left[dstPos] + (s32) gSynthesisReverb.ringBuffer.right[dstPos]) / 2); + 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]; } } @@ -410,31 +419,12 @@ void prepare_reverb_ring_buffer(s32 chunkLen, u32 updateIndex) { 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]); - - // for (srcPos = 0, dstPos = item->startPos; dstPos < item->lengthA / 2 + item->startPos; - // srcPos += gReverbDownsampleRate, dstPos++) { - // gSynthesisReverb.ringBuffer.left[dstPos] = reverb_sample_left(item->toDownsampleLeft[srcPos]); - // gSynthesisReverb.ringBuffer.right[dstPos] = reverb_sample_right(item->toDownsampleRight[srcPos]); - // } - // for (dstPos = 0; dstPos < item->lengthB / 2; srcPos += gReverbDownsampleRate, dstPos++) { - // gSynthesisReverb.ringBuffer.left[dstPos] = reverb_sample_left(item->toDownsampleLeft[srcPos]); - // gSynthesisReverb.ringBuffer.right[dstPos] = reverb_sample_right(item->toDownsampleRight[srcPos]); - // } } else { // Too slow for practical use, not recommended most of the time. 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 = item->startPos; dstPos < item->lengthA / 2 + item->startPos; dstPos++) { - // gSynthesisReverb.ringBuffer.left[dstPos] = reverb_sample_left(gSynthesisReverb.ringBuffer.left[dstPos]); - // gSynthesisReverb.ringBuffer.right[dstPos] = reverb_sample_right(gSynthesisReverb.ringBuffer.right[dstPos]); - // } - // for (dstPos = 0; dstPos < item->lengthB / 2; srcPos += gReverbDownsampleRate, dstPos++) { - // gSynthesisReverb.ringBuffer.left[dstPos] = reverb_sample_left(gSynthesisReverb.ringBuffer.left[dstPos]); - // gSynthesisReverb.ringBuffer.right[dstPos] = reverb_sample_right(gSynthesisReverb.ringBuffer.right[dstPos]); - // } } } } @@ -597,6 +587,22 @@ 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; + } + if (reverbFilterCount > NUM_ALLPASS) + reverbFilterCount = NUM_ALLPASS; + reverbFilterCountm1 = reverbFilterCount - 1; + if (reverbFilterCount < 3) + reverbFilterCountm1 = 0; +#endif + for (i = gAudioUpdatesPerFrame; i > 0; i--) { if (i == 1) { // 'bufLen' will automatically be divisible by 8, no need to round diff --git a/src/audio/synthesis.h b/src/audio/synthesis.h index 19f341ab..ee1d96ce 100644 --- a/src/audio/synthesis.h +++ b/src/audio/synthesis.h @@ -18,22 +18,40 @@ #endif #ifdef BETTER_REVERB -#define BETTER_REVERB_SIZE 0xF200 // Size determined by ((all delaysBaseline values * 16) / (2 ^ Minimum Downsample Factor)) + array pointers; can be increased if needed -// #define BETTER_REVERB_SIZE 0x1E200 // For use with a downsampling value of 1 (i.e. no downsampling at all) -#else -#define BETTER_REVERB_SIZE 0 -#endif + // Size determined by ((all delaysBaselineL/R values * 8) / (2 ^ Minimum Downsample Factor)) + array pointers. + // The default value can be increased or decreased in conjunction with the values in delaysBaselineL/R +#define BETTER_REVERB_SIZE 0xF200 + +// #define BETTER_REVERB_SIZE 0x7A00 // Default for use only with a downsampling value of 3 (i.e. double the emulator default) +// #define BETTER_REVERB_SIZE 0x1E200 // Default for use with a downsampling value of 1 (i.e. no downsampling at all) #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. +extern s8 betterReverbDownsampleConsole; +extern s8 betterReverbDownsampleEmulator; +extern u32 reverbFilterCountConsole; +extern u32 reverbFilterCountEmulator; +extern u8 monoReverbConsole; +extern u8 monoReverbEmulator; extern s32 betterReverbWindowsSize; -extern const s32 delaysBaseline[NUM_ALLPASS]; -extern s32 delays[NUM_ALLPASS]; -extern s32 ***delayBufs; +extern s32 gReverbRevIndex; +extern s32 gReverbGainIndex; +extern s32 gReverbWetSigna; +// extern s32 gReverbDrySignal; + +extern const s32 delaysBaselineL[NUM_ALLPASS]; +extern const s32 delaysBaselineR[NUM_ALLPASS]; +extern s32 delaysL[NUM_ALLPASS]; +extern s32 delaysR[NUM_ALLPASS]; +extern s32 reverbMultsL[NUM_ALLPASS / 3]; +extern s32 reverbMultsR[NUM_ALLPASS / 3]; +extern s32 **delayBufsL; +extern s32 **delayBufsR; extern u8 toggleBetterReverb; -extern s8 betterReverbConsoleDownsample; -extern s8 betterReverbEmulatorDownsample; +#else +#define BETTER_REVERB_SIZE 0 +#endif struct ReverbRingBufferItem { diff --git a/src/game/behaviors/snow_mound.inc.c b/src/game/behaviors/snow_mound.inc.c index f8fcc539..b9bfb978 100644 --- a/src/game/behaviors/snow_mound.inc.c +++ b/src/game/behaviors/snow_mound.inc.c @@ -33,7 +33,7 @@ void bhv_snow_mound_spawn_loop(void) { if (o->oTimer == 64 || o->oTimer == 128 || o->oTimer == 192 || o->oTimer == 224 || o->oTimer == 256) sp1C = spawn_object(o, MODEL_SL_SNOW_TRIANGLE, bhvSlidingSnowMound); - if (o->oTimer == 256) { + if (sp1C && o->oTimer == 256) { sp1C->header.gfx.scale[0] = 2.0f; sp1C->header.gfx.scale[1] = 2.0f; }