Bank load status functions in RuntimeManager erroneously report banks as loaded while loading asynchronously

I’ve been implementing some pretty granular bank loading in a project that is shipping on mobile, and I have been having some troubles with manually handling bank loading.

For a start, the RuntimeManager.LoadBank() function is thread-blocking by default. I had to modify this to include an option for specifying loading flags, so that I would be able to set banks to load using NONBLOCKING instead of NORMAL

That’s fine, but then I found that if I set a bank to load with the NONBLOCKING flag, then immediately query the HasBankLoaded(), HaveAllBanksLoaded(), or AnySampleDataLoading() functions in the RuntimeManager, each of them will report that the bank has finished loading right away, even though the asynchronous load hasn’t completed.

I believe that this is the case because I’m running a coroutine that checks for the status of bank loading and creates an instance of a sound once its bank has loaded, and when I set the bank to load asynchronously, it attempts to fire off the event too early, erroring out. It doesn’t matter whether I check any or all of those functions, the result is the same.

In cases where I can know in advance that a bank will be required shortly, this isn’t an issue. But for the cases where I need to load a bank and play a sound from it as soon as possible, I have had to load these banks with the NORMAL flag, which is far from ideal.

One other thing to note is that the load times of the banks using thread-blocking loading are clearly visible in the Unity Profiler using Deep Profiling, but that they show no impact at all in the FMOD Profiler, which seems odd — in fact, the memory read-out in the FMOD Profiler doesn’t change when I load and unload banks either, further adding to my confusion.

Is there a way to reliably check whether an async bank is currently loading?

For context, I’m working in Unity 6000.0.55f1 and FMOD 2.02.18

Changing the loading mode to NONBLOCKING would cause loadBank to return immediately and short-circuit the logic for HasBankLoaded and HaveAllBanksLoaded, since they are just checking for a map entry and loadingBanksRef respectively.

As for AnySampleDataLoading, I see there’s no error check for whether the bank has loaded successfully. Calling getSampleLoadingState on a NONBLOCKING bank that hasn’t finished loading would return an error, and the load state would be UNLOADED, causing AnySampleDataLoading would return false, giving you a false positive that the whole operation has been completed when really it hasn’t begun at all.

For the case where you need to load a bank and play a sound as quickly as possible you need NORMAL/blocking bank loading don’t you? NONBLOCKING isn’t going to speed anything up- perhaps I misunderstand your meaning here.

That does sound odd, can you please provide a screenshot of the load time discrepancy between the FMOD Profiler and the Unity Profiler?

In the “load_bank” FMOD Engine example we demonstrate how to poll a combination of the bank load and sample data load states to determine when a NONBLOCKING bank is finished loading. Essentially you want to poll Bank.getLoadingState until it is LOADING_STATE.LOADED, and then poll Bank.getSampleLoadingState until that returns LOADING_STATE.LOADED. After that, you can be certain that the NONBLOCKING load has completed successfully.

1 Like

In this instance I would rather play the sound after a short delay than cause a frame hitch. To make the delay as short as possible, I want to check the bank load status each frame and trigger the event as soon as the bank has finished loading, but that requires knowing the load status.

I hadn’t tried polling the bank directly in this way because I couldn’t find any information on how to actually access a bank struct — I’ve finally found that I can use the Runtime Manager to get the Studio System instance, which in turn has a function to return a bank object that I can call these functions on. Is this covered in the documentation anywhere? If so I haven’t been able to find it.

With that, I think I’ve got what I need to manage this now, thanks!

I wasn’t able to reproduce this, I think I must have been wrong about it. It’s possible that I just couldn’t see the impact of loading/unloading very small banks in the FMOD Profiler, since the initial memory spike of starting the profiler session blows out the scale of the I/O row.

This screenshot is of loading a very small bank asynchronously, and even after stretching out the File I/O row this far it’s only barely visible as a block a single pixel tall, so it’s easy to miss that it even happened.

The RuntimeManager doc mentions a few of things you can expect to access through the RuntimeManager, including the various System instances and bank objects, but I suppose the details on what you can do with those are hidden away in the API docs.

There isn’t anything explicit about how to get from the RuntimeManger all the way down to a FMOD::Studio::Bank. I’m thinking perhaps we could add the diagram from our FMOD for Unity page and explain the separation between the Integration, Studio, and Core APIs, and how to move between them. Would that help bridge the concepts better? Otherwise, is there anything you can think of adding that would have made it easier to bridge the gaps between these concepts?

Well I didn’t even know that that FMOD for Unity page existed, since it doesn’t come up under the Learn menu. It also seems more like a sales pitch than a reference doc, so I probably wouldn’t look at it even if I did know where it was.

I don’t think it’s clear that the Engine docs are actually relevant to people using the Unity or Unreal integrations — it seems obvious enough to go through the Scripting API section of the Unity Integration docs, but it took me some time to realise that I actually needed to consult the Engine docs to find out certain things.

For example, so far as I can find there is never any mention of the Bank struct in the Unity documentation, only ever bank reference strings, or the StudioBankLoader component.

What I think would be most helpful is if the subsections of the Unity Integration Scripting API Reference had links to the relevant parts of the Engine docs, so that a person searching for “bank” in the Unity docs will eventually be able to find their way to the Bank.getLoadingState and Bank.getSampleLoadingState functions you mentioned above. I didn’t know those even existed until you told me, I had assumed it was outside the scope of what I had access to in Unity.