Now that the VST is released for my app (spacecraft granular synth) I have returned my attention to the Android version. The only thing that’s stopping me from releasing this right now is the dreaded CPU scaling that only happens on a subset of devices. I’m finding that a low-cost basic device such as Xiaomi Mi is able to run my app flawlessly, but a powerful flagship such as the Note 8 has audio glitches which are corelated to downward spikes in the CPU frequency (I’ve ruled out GUI/resolution as the culprit).
After lots of optimisation of the DSP, one of the last remaining possible fixes for this that I’m aware of is the Oboe ‘StabilizedCallback’, thanks to @donturner for pointing me in the right direction. After many failed attempts, I’ve finally managed to get this to work (I think) in JUCE.
Here’s my implementation (modifications to juce_android_Oboe.cpp). Note that this is just a prototype implementation with a standard pointer, I still need to figure out what happens with object destruction and whether or not smart pointers are needed (any suggestions welcome).
Declaration of a pointer to an AudioStreamCallback object in the OboeStream class:
oboe::AudioStreamCallback * asc;
Replace this line of code in the same class…
if ( callback != NULL )
asc = new oboe::StabilizedCallback(callback);
- Release build
- Link-time optimisation enabled
- Optimisation: Ofast
- Oboe release v1.2.0
By adding the check for NULL I can finally run my app without crashing on start-up. The stabilized callback appears to be working; however, although as the cpu frequency profile and audio glitches appear to be improved, there are still sporadic drops in cpu freq and corresponding audio dropouts. Saying that, there is a huge number of settings (such as optimisation settings in jucer etc.) that I need to try before it can be conclusive.
So, I have a couple of questions going forward for @donturner.
Firstly, I notice that in StabilizedCallback.cpp there are some hardcoded parameters:
constexpr int32_t kLoadGenerationStepSizeNanos = 20000;
constexpr float kPercentageOfCallbackToUse = 0.8;
Can these parameters be thought of as tuning parameters for the stabilized callback? If I increase those numbers, does the stabilized callback become more ‘stabilisy’? If so, do you have any guidelines for tuning (max limits etc.)?
Secondly, in the scenario that the StabilizedCallback alone does not fix the issue, an additional modification could be for Oboe to use a larger buffer (latency is not so important in my app as it’s predominantly generative). Perhaps this, in combination with the StabilizedCallback, would help me find a sweet spot which would eliminate dropouts on my Galaxy Note 8. Questions relating to this:
- What is the proper way to increase the buffer size in Oboe? I’ve tried changing oboe::PerformanceMode::LowLatency to oboe::PerformanceMode::None or oboe::PerformanceMode::PowerSaving however, this results in very large audio dropouts (even with a barebones hello world JUCE app generating a sine wave)
- If buffer size modifications are possible, how could I control this within my app? (this might be more a question for the JUCE devs)