Hello community!
I have a question regarding sound bank size and optimization. A bit of context:
The game I am developing currently is a mobile-first hero collector. Until now, for all hero-specific sounds, I followed the principle of keeping sound banks separated by hero, so that memory usage can be optimized by only loading the banks of the heroes currently participating in a battle into memory.
The asset bank size on mobile averages at about 2.2MB / hero, with 6MB being the biggest one for a boss.
Since I’ve already designed quite a lot of assets I’m getting to a point where I can re-use quite a lot of them.
Now the questions:
From my research into FMOD bank optimization I gather that if I have an asset re-used in two or more independent banks, it will occupy disk space in each of the banks, but should I load multiple banks containing the same asset, the duplicated asset will only be loaded once into memory, is this correct?
My ideal scenario would be re-using assets in different sound banks without increasing disk usage due to asset duplication. Is there any way to do this in FMOD?
The reason I’m asking is because I need to decide if it’s worth abandoning the one bank per hero idea and instead putting all hero sounds in one big bank, which will continue growing, but due to asset reutilization probably will reach a point where it will grow very little upon adding more heroes. Currently, all my character banks combined rank up to 127MB on mobile.
Looking forward to hearing your thoughts / suggestions on this topic.
Each bank in FMOD Studio represents a specific bank file to be built; assigning an event to a bank tells FMOD Studio to include it in that bank file. There is no way to assign an event to a bank without including its assets in the bank file, because bank files are designed to function as loading units, where loading a bank makes it possible to play every event assigned to that bank without further loading being necessary.
As such, if you do not want an event’s assets to be in multiple banks, the simplest way to do it is to avoid assigning that event to multiple banks. There are a few different ways to do this; putting absolutely everything in one bank, as you have already considered, is one possibility, but far from the only one.
Have you considered a hybrid approach of having hero-specific banks as you currently do, but of also having a bank that contains all the events that are used by multiple different heroes? This would allow you to keep most of the advantages of hero-specific banks (only requiring the banks associated with the currently-participating heroes to be loaded into memory at any given time), without requiring assets to be duplicated across multiple banks.
If only some of the assets in an event are shared with other events, but not all, there’s a way to handle that, too. if you look in the build tab of the preferences dialog, you’ll see a checkbox marked “include referenced events in banks (reccomended).” If you uncheck this checkbox, nested and referenced events will no longer be automatically included in the same banks as the events that reference them. This means you can manually assign them to specific banks, allowing you to precisely control when those banks are loaded independent of the banks to which their parent events are assigned - potentially meaning that you could place all the shared assets in nested events assigned to a shared bank that can be loaded independently of the hero-specific banks.
I should mention that each bank file necessarily includes a small amount of overhead. This means that even if assets aren’t duplicated across banks, one giant bank that contains everything will have a smaller total size than a large number of banks that each contain a subset of that content.
Unfortunately, there is no single best practice that I can point you towards, because every game is different, and every way of structuring your banks has different advantages and disadvantages. Having a small number of large banks reduces the total size on disk and thus the total download size of your game, but also increases the amount of memory required to load that bank; whereas having a large number of small banks increases the total size on disk, but allows you to save memory by only loading the banks you currently need, and potentially allows you to save on both download size and disk storage requirements by deferring the download of banks that the player doesn’t immediately require until they need them. You will have to try different options and see what works best for your game.
The approach of using a generic bank with more common sounds that repeat a lot, and then keeping only special hero sounds in individual sound banks seems to be a fantastic solution!
I’m looking into it already!
Let me ask a follow-up:
I was recently profiling my game and also had the FMOD overlay active in Unity. As mentioned above, my hero sound banks currently total to about 150MB. Also, FMOD is currently set to load all banks into memory at startup (we’ll implement the individual bank loading later).
Now, if FMOD is set to load all banks in memory, shouldn’t the memory info show something close to the sum total of the size of my sound banks? I’m asking because it only registered about 37MB, which makes me wonder how exactly assets are loaded into memory…
In practice, this means that unless you explicitly choose to load a bank’s sampledata in advance, it is loaded piecemeal only as needed to play the event instances you’ve created, and is automatically unloaded from memory when those event instances have been destroyed and the sample data is no longer needed. This helps keep memory consumption low, but can in some cases result in a small but discernible amount of latency between starting the event instance and the event instance actually starting, to allow the sample data time to finish loading.
If that latency is problematic, you can avoid it by explicitly loading the sample data associated with a specific event or bank ahead of time. In Unity, this can be done on a per-event basis by checking the Preload Sample Data checkbox of a Studio Event Emitter component, or on a per-bank basis by selecting “Load Bank Sample Data” in the Studio Bank Loader. If you’re using Unity Visual Script, you also have the option of checking the “Load Samples” checkbox on the Load Bank visual scripting unit as shown in our documentation.