I've written a game plugin which I would like to see included in the official Rockbox distribution. Everything is working across all colour players (and others get an unsupported message) apart from one piece of unexpected behaviour. My player is a Fuze v2.
During the initialization part of a new game I have a CPU intensive and highly recursive function called 'calculate_par' (CP). If this function is invoked while RB is playing a track, the playback is often stopped partway through evaluating CP. This problem can be replicated on the emulator, but CP seems to be able to run on a bigger dataset before it manifests. I'm looking for some ideas about how to identify the reason for this and how to fix it.
I've written a bunch of test case scripts to see if I can replicate the problem (see footnotes for the code):
- Max out the CPU using a loop. This causes playback to pause after a bit, but it resumes when the script exits. rb.yield() stopped the pause entirely. (1)
- Do a lot of recursion. This didn't have any effect with rb.yield() enabled. (2)
- Keep filling a table until playback stops. This replicated the permanent stop. Interestingly, both the emulator and actual device stopped with an 'i' value of 16,386 (which equals 2^14+2). (3)
I've tried putting a rb.yield() after every statement in the CP function tree, this had no apparent effect on the device, but increased the threshold on the computer beyond what I could easily test. I put in some logging commands in CP and found that the depth of recursion reached before playback stopped was anywhere between 95 and 250. The memory used by Lua (as returned by collectgarbage("count")) was similarly variable, going from 250 to 400 before the playback stopped.
I spent a reasonably amount of time optimising CP for speed (it went from ~30s to ~1s for one data set), and is well suited to a recursive approach. As such I'd rather not rewrite it using iteration, especially when I'm not sure that the problem is a recursion limit.
If I can't get this to work, I probably have the option of just calling something like rb.audio_resume() when CP finishes (if required). Is this hack-ish solution likely to be accepted?
Test scripts:(1) Max CPU
i=0
for i=1,1000000 do
rb.yield()
i = i + 1
end
(2) Lots of recursion
function recurse(num)
rb.yield()
if num == 0 then
return 0
else
return recurse(num - 1)
end
end
recurse(1000000)
(3) Table filling
table={}
i=1
while rb.audio_status() == 1 do
table[i] = "blh"
i = i + 1
rb.yield()
end
rb.splash(300, i)
rb.splash(300, collectgarbage("count"))