We’re on playing .mid file(with custom dls) using Low Level API(FMOD 5) on iOS.
It was impressive that runtime manipulation with setMusicSpeed / setMusicChannelVolume.
[ In fact, we want more controls based on the midi messages, but we don’t want bother you with that ]
After some testing, we found that once the speed of music has changed in runtime,
sound::setPosition was inconsistent(esp. the first time the speed was ever changed) and getPosision seems to return x1-speed-based timeline value no matter what type(ms or PCM, etc.) is.
It might be ignorable with a one-shot midifile (resolved with length = -1 in FMOD_CREATESOUNDEXINFO), but it’s critical when we want to use a looping background music with dynamic tempo change according to the various situation.
We tested it using FMOD 4(FMOD Ex) but the result was same.
Are there any workaround to handle this?
Thanks in advance.
You must be careful with setMusicSpeed, it’s a bit unusual in how it works. It was marked for deprecation in FMOD 4 yet through workarounds has remained useful for some developers, hence it remains.
Firstly, you should always use FMOD_CREATESOUNDEXINFO.length = -1 when using setMusicSpeed as only the codec understands the speed changes, the FMOD::Sound does not. There aren’t any current plans to try and resolve this issue, but it has been attempted before and was determined non-trivial.
As a first pass, you may want to open the file without length = -1 and without using any setMusicSpeed so you know the correct length of the file.
Next up you need to know that any call to getPosition will tell you how many samples have been generated by the MIDI synth. If you speed up the playback engine with setMusicSpeed you will get through more of the MIDI, but still produce the same number of samples per second.
To know exactly where you are in the file you must call getPosition each time you change the music speed and accumulate the real position yourself by multiplying the music speed by the difference in getPosition calls. Let me know if this doesn’t make sense
If you want to setPosition to a time in the future, use your calculated getPosition as the base and add the number of samples taking into account the current music speed. If you want to seek backwards or to any exact location first call setPosition(0), then setPosition with the absolute position multiplied by the current music speed.
You will need to handle looping yourself by tracking your current position or fix up loop points each time the speed changes.
As you can see there are a lot of caveats with this feature, hence why it was going to be deprecated. If your careful I think you can make it work for you though, however far from elegant.