Skip to content

BETTER_REVERB Documentation

Gregory Heskett edited this page Aug 12, 2024 · 23 revisions

Summary

The "BETTER_REVERB" patch is designed to override vanilla Super Mario 64's idea of reverb, which really is just nothing more than a basic echo effect. This patch aims to bring in a much more convincing soundscape that can allow your hack's music and environment to really stand out.

BETTER_REVERB uses an optimized CPU algorithm that makes it suitable for use with console hacks when fed the right parameters. Although, keep in mind that it will generally still eat a fair bit of CPU when in use, with scattered memory accesses that can also affect RSP/RDP performance. It is important to be conservative with your preset parameter selections in performance-heavy situations, especially if you want to support console. BETTER_REVERB's runtime demand on its own is always constant, and will not change unless the preset it's using changes. More details relating to performance can be found in the presets section.

Note that this specific documentation only applies to HackerSM64 versions 2.1 or newer.

Setup

To use BETTER_REVERB, uncomment the define that can be located in include/config/config_audio.h. To actually use in game, you must override the SET_BACKGROUND_MUSIC or SET_MENU_MUSIC commands in the level script with SET_BACKGROUND_MUSIC_WITH_REVERB or SET_MENU_MUSIC_WITH_REVERB respectively.

  • SET_BACKGROUND_MUSIC_WITH_REVERB takes in four arguments:

    • settingsPreset - The vanilla reverb preset to be used with the sequence. When using your own BETTER_REVERB presets that are not set to fall back to the vanilla settings, this argument becomes relatively unimportant.
    • seq - The ID of the sequence you want to play for your area. To play no background music, submit this command with SEQ_SOUND_PLAYER as an input.
    • reverbPresetConsole - BETTER_REVERB preset ID to use when playing on console.
    • reverbPresetEmulator - BETTER_REVERB preset ID to use when playing on emulator.
  • SET_MENU_MUSIC_WITH_REVERB takes in three arguments:

    • seq - The ID of the sequence you want to play for your menu. To play no background music, submit this command with SEQ_SOUND_PLAYER as an input.
    • reverbPresetConsole - BETTER_REVERB preset ID to use when playing on console.
    • reverbPresetEmulator - BETTER_REVERB preset ID to use when playing on emulator.

The list of BETTER_REVERB presets to choose from is defined in src/audio/data.c and can be edited to include custom presets as desirable. When using the vanilla level script commands without preset specifications, BETTER_REVERB preset 0 will always be selected (which by default is set to use vanilla reverb). There are eventual plans to integrate native support for this into fast64, which will eliminate the need for manually overriding the level script commands with custom exports.

BETTER_REVERB Presets

Main Parameters

BETTER_REVERB presets are located in src/audio/data.c. Here is a description of the parameters in order:

  • useLightweightSettings

    • This will offer an extra boost of performance, while trading off some configurability.
    • Please see the lightweight parameters section for more details.
  • downsampleRate

    • This value lowers the resolution of the incoming audio signal exponentially, which can help to lower game performance or reduce some higher frequencies in the response.
    • A value of 1 represents no downsampling, 2 cuts the sample rate in half, and 3 cuts it into a quarter, etc. This also corresponds directly with memory requirements. Downsampling can reduce the reverb's quality in a hurry, most noticeably at around 3+. Values larger than 5 or so may be unstable and lead to game crashes.
    • Values of 0 and below can be used to disable BETTER_REVERB entirely, and opt to use vanilla reverb instead. Opting for vanilla reverb can also be a good CPU saving measure if necessary, or if detailed reverb is just not needed for a particular area.
  • isMono

    • Reverb will be downmixed and processed only on a single channel, in order to create a mono signal.
    • This can help to nearly double performance, but really adversely affects the immersion of the soundscape.
    • It is almost never recommended to use this setting.
  • filterCount

    • This represents the number of all-pass filters to use when processing the reverb.
    • Filter count must always be a multiple of and no less than 3, and will always be no greater than NUM_ALLPASS defined in src/audio/syntheses.h.
    • More filters provide additional quality and a more enriched sound at the cost of additional performance and memory usage.
    • When needing to optimize for performance, this is the first recommended value to decrease in most circumstances.
    • Value overridden when useLightweightSetting is enabled.
  • windowSize

    • The sample size of the main reverb circular buffer.
    • This corresponds almost directly with sound delay. Larger values will take longer to circulate back to the beginning, which makes the sound feel more distant and open. Smaller values would be recommended for enclosed spaces.
    • Smaller values will also decay a bit faster than larger values.
    • A negative window size value will fall back to using the vanilla preset value. Values that are otherwise too small or too large will be automatically resized as necessary in order to not cause fatal issues in the game.
    • A window size of exactly 0 can be used to disable ALL reverb, including the effects of vanilla reverb. This will save a very significant amount of performance overhead, but is generally not recommended as it is atypical of even vanilla SM64 to do this.
  • gain

    • How much of the final signal to retransmit back into the input circular buffer.
    • This corresponds almost directly with sound decay. Larger values will take much longer for the sound to fade out, and vice versa.
    • A negative gain value will fall back to using the vanilla preset value.
    • Be careful with this parameter; values that are too high can result in some terrible feedback!
  • gainIndex

    • Advanced parameter; affects the signal immediately retransmitted back into the filter buffers.
    • Mostly used to tune the first 2 of every 3 filters.
    • Mid-high values typically yield the strongest effect.
    • Value overridden when useLightweightSetting is enabled.
  • reverbIndex

    • Advanced parameter; affects the intensity of the signal transmitted into the next group of 3 filters.
    • Mostly used to tune the result coming from the last of every 3 filters.
    • The filters are cyclic, therefore using only one grouping of 3 filters does not render this parameter useless.
    • Be careful with this parameter; values that are too high can result in some terrible feedback!
    • Value overridden when useLightweightSetting is enabled.
  • *delaysL and *delaysR

    • Advanced parameters; pointers to an array of values that represent the buffer sizes of each respective filter.
    • Larger buffer sizes correspond to increased signal delay.
    • In general, these are most balanced when the cumulative total of each group of 3 filters is similar between left and right but also not matching one another.
    • Larger buffers require allocating more memory in-game.
  • *reverbMultsL and *reverbMultsR

    • Advanced parameters; pointers to an array of values that represent multipliers for the final output signal of each group of 3 filters.
    • This differs from reverbIndex in that it is only applied to the final output signal. reverbIndex does not get applied to the final output signal directly at all.
    • Differing left and right values can add a bit of stereo depth to your sound, but may be somewhat difficult to balance properly. When only using 3 filters, the left and right values will be averaged together to help counteract this potential imbalance.
    • These settings are ignored when using lightweight settings.
    • Values unused when useLightweightSetting is enabled.

Lightweight Parameters

When useLightweightSettings is enabled in your BETTER_REVERB preset, some of the other parameters will be overridden by special constants defined in src/audio/synthesis.h. By using precompiled constants with predictive behaviors, BETTER_REVERB can instead run a more optimized function that can reduce CPU overhead substantially. These constants are not configurable at runtime however, and the lightweight parameters will apply to every single preset with useLightweightSettings enabled. Keep this in mind in order to make the most out of balancing your aesthetic desires with your game's runtime performance.

Here is a description of the lightweight parameters in order:

  • BETTER_REVERB_FILTER_COUNT_LIGHT

    • Overrides filterCount
    • This represents the number of all-pass filters to use when processing the reverb.
    • The lightweight filter count setting is special in that it does not need to be a multiple of 3.
      • Values from 1 to NUM_ALLPASS are all valid, although 2 is usually recommended. A value of 1 will improve performance at the cost of saturation, while values larger than 2 can offset the performance benefits of using lightweight settings in the first place.
      • This will behave differently to that of non-lightweight in all cases, but the default value of 2 will sound most comparable to a non-lightweight value of 3.
  • BETTER_REVERB_GAIN_INDEX_LIGHT

    • Overrides gainIndex
    • Advanced parameter; affects the signal immediately retransmitted back into a filter or the next filter in the chain.
  • BETTER_REVERB_REVERB_INDEX_LIGHT

    • Overrides reverbIndex
    • Advanced parameter; affects the intensity of the signal from the last filter retransmitted back into the first filter.

Additional Notes

  • When using a set of demanding parameters for emulator, any emulators that are using a counter factor greater than 1 or that are not overclocking CPU can suffer horribly and pretty much render the game unplayable. With no performance restrictions whatsoever, even counter factor 1 may not be good enough to run at full speed, or at the very least may increase level load times dramatically.

    • To get around this problem, please enable RCVI Hack in include/config/config_rom.h.
    • If you do not want to use RCVI Hack, try to keep your emulator presets in check with console-acceptable requirements, or just share the same preset between console and emulator (assuming said preset actually runs sufficiently on console).
  • IMPORTANT: If after changing the parameters, you hear developing noise that keeps increasing in intensity, this likely indicates a usage of unstable reverb parameters.

    • This is known as sound feedback. If this happens, stop immediately and reduce any suspect parameters. Noise like this at high enough volumes can be potentially very destructive to both your sound equipment and your hearing (not to mention, your game's enjoyability).
    • Checks to prevent this have not been implemented in order to maximize performance potential, so choose your parameters wisely. The current parameter defaults are safe and will not have this problem.
    • Generally speaking, a sound that doesn't seem to be fading at a somewhat natural rate is a parameter red flag. When in doubt, it's best to be conservative and save yourself the risk of destroying your game's sound.
  • BETTER_REVERB requires a lot of memory, but you may not need to use all of it if you're interested in performance.

    • Memory allocation is defined by BETTER_REVERB_SIZE in src/audio/synthesis.h, and can be adjusted as needed to optimize and not waste memory usage.
    • To get a better idea of how much memory is actually being used at any point in time, enable PUPPYPRINT_DEBUG in include/config/config_debug.h and look at the Audio page.
    • If an insufficient amount of memory has been allocated, an assertion should be thrown that will trigger an immediate game crash. This is to prevent the alternative option, which most likely would manifest itself in the form of either an unrelated crash or some seriously unpleasant game audio.
  • For a more specific perspective on roughly (albeit not exactly) what's going on under the hood, please reference this diagram.

Proper Application and Usage

The amount of reverb that gets processed can be controlled by three different elements:

  • Area Presets

    • These values are defined in levels/level_defines.h.
    • Each area preset adds a static value to the amount of reverb that gets processed for every sound effect for that area (excluding sounds that disable reverb outright). These are the same echo parameters that can be set in fast64. Presets can only support up to three areas per level, so any areas beyond this will fall back to the third area's preset.
    • Alternatively, the SET_ECHO level script command can be employed to override the values in levels/level_defines.h. This is usable for any number of areas in a level, so it will not be doomed to falling back to the third area's value if you have more than 3. This can also differentiate values for console and emulator.
      • SET_ECHO takes in two arguments:
        • console - The area echo to be used when playing on console
        • emulator - The area echo to be used when playing on emulator
  • Individual SFX

    • Mini sequences for every sound effect are defined in sound/sequences/00_sound_player.s.
    • For any sound you wish to adjust the presence of reverb to, apply the .set_reverb command appropriately. See examples of how other sounds use it to get a better feel behind how it works.
  • M64 Sequences

    • Each individual sequence channel supports an Effect parameter that can be set to it. This command is represented by 0xD4 in the game. MIDI files that are imported into SEQ64 for conversion can also represent it using CC 91.
    • M64 sequence parameters are not influenced by area presets nor individual sfx parameters.

In-Game Testing

Need help optimizing a reverb preset? Puppyprint Debug has two features that can help you both fine tune reverb presets and optimize it for performance. To enable, uncomment the define for PUPPYPRINT_DEBUG in include/config/config_debug.h.

Profiling

In the Puppyprint Debugger, go to the Audio page. There, you will see a breakdown for the audio runtimes and memory usage.

  • All of BETTER_REVERB's runtime will be reflected as part of Reverb profiling. BETTER_REVERB's performance demand is very stable and will not fluctuate much unless swapping presets, however the report may still waver a little based on unrelated factors bundled into the same category. Check the runtime report in a place like a level's act selector for the most stable readings. Note that any performance readings on emulators will most likely be extremely inaccurate to real hardware.

  • BETTER_REVERB's memory requirements are predictable and will never change until a new preset is used. You can see how much memory in the pool is occupied at any given time, and you can also reduce the BETTER_REVERB memory reservations in src/audio/synthesis.h appropriately in order to save on global memory. If not enough memory is allocated when a preset is used, the game should fail an assertion check and instantly crash.

Preset Testing

In the Puppyprint Debugger, go to the Reverb Config page. There, you will be provided a list of preset options to play around with. Every main reverb parameter can be adjusted in this menu, in addition to the Area Echo for sound effects.

There are two testing presets that you can switch between for A/B testing. These are designed with efficiency in mind to minimize the amount of time needed to produce a quality preset that can be copied into the game code.

Lightweight parameters, Delays arrays, and Reverb Mults arrays can be assigned, but not configured during runtime. Any adjustments must be made prior to compiling the game.

Additional Help

Please ask any additional questions that are not covered satisfactorily by this documentation in the HackerN64 Discord. BETTER_REVERB was implemented by ArcticJaguar725, who will be the most knowledgeable candidate to answer any individual questions.