I gave writing a plugin to read Opus files with the FMOD Low Level API another go (with a failed attempt earlier) and I’ve finally succeeded. The issue, now: it’s extremely slow!
It seems that FMOD gets all of the PCM data during the
system->createSound call. That means opusfile needs to decode all of the data, which takes up a considerable amount of cycles, and therefore a lot of time.
Re-encoded Thai Opus 64kbps time: 1.934518s
Re-encoded Thai Opus 96kbps time: 2.088251s
Original source Thai MP3 time: 0.960078s
So, basically, my test files (a random funny Thai song
from a totally legitimate source) show that using my plugin causes a 2-3.5x increase in time to load. Yikes!
So, my question is as follows: is there a way to make FMOD decode audio on-the-fly?
I’m not quite sure how I can use the stream from FMOD either, so I’m copying the entire file into another buffer inside my
open callback. To me, memory usage is negligible as long as it’s sane. I’m not sure this is really part of the slowness.
I’d be happy to share my plugin code if it helps.
posting here because I accidently answered offline.
The increase in time will be the extra complexity of the codec. Opus is far more expensive to decode than MP3.
If you mean ‘on the fly’ as in ‘FMOD_CREATECOMPRESSEDSAMPLE’ style, that is limited to internally supported codecs. Streaming is the other way that will support external codecs like yours.
A way to decode a sound ‘offline’ into a PCM buffer is to use Sound::readData from the app. To avoid the decode overhead of createSound you can use FMOD_OPENONLY flag with createSound or createStream.
createSound will still allocate memory for the whole decompressed sound (which can be a lot), so createStream can be beneficial here if you want a smaller buffer/memory overhead, even if FMOD_OPENONLY means nothing is decoded at the point of opening.
This is mainly used for offline decoding (ie displaying the waveform on screen). If you wanted to play it, you would have to create another stream and call readData from a custom callback based stream. This might be somewhat pointless, as you might as well play it as a stream if you wanted to just play the stream in chunks.
Because you loaded the opus into memory, just open the stream with FMOD_OPENMEMORY (pointing it to your buffer), and disregard all the FMOD_OPENONLY/readData stuff I just talked about if you just want to play it without the initial overhead.
FMOD_NONBLOCKING also helps it will give you no overhead on the createStream call.