I’m playing with a rhythm gameplay and I run into an issue with fileplayer. I prepared a minimal example and tried to test a lot, so hopefully it’s not something wrong with me — I’m definitely not a drummer
EDIT: I tested the issue with sampleplayer and the results are very similar. Not sure what to make of that, as in the case of fileplayer, I expected it to be some kind of a buffering issue. I edited the title to reflect that. The sampleplayer issue should be reproducible with the modified example included below.
I’m using a 120 bpm music file with beats nicely aligned with the half/full seconds — I can reliably hit these in Simulator (on macOS) but tapping on beat on device (revA) returns values that seem to be sliding off (by up to ~0.2s). The deviation seems to be changing over time, so below are values from about a minute and half into the music track. However, it’s noticeable right away.
local player = playdate.sound.fileplayer.new("120bpm")
player:play(0)
function playdate.update()
if playdate.buttonJustPressed(playdate.kButtonA) then
print(player:getOffset())
end
end
Looking at your code there's no refresh rate defined. So it will be running at 30fps. This could mean that, depending on how/when the SDK polls button presses, there could be up to 0.0333s of delay for each button press.
But that would only explain half of the difference.
buttonJustPressed means pressed and released so is slow when compared to buttonIsPressed which only concerns itself with the press (and not the release).
There's also button debounce. Not sure if that applies to Simulator.
Ah, I may have oversimplified the example — i’m running the code at 50 fps. (I’ll test with a fixed example to be sure.)
The buttonJustPressed should be the keyDown equivalent (in browser JS terms), but I’ll try a different way to check the button for sure (I normally use getButtonState but went with this for simplicity when prototyping).
Re debounce: it did not occur to me that this could be a more general issue with input. I’ll try to find a way to check how quickly playdate reads the input (perhaps with a high framerate rec in my phone). But 150+ ms sounds a bit too much for me not to notice before.
This is the example source I posted above running at 50 fps, checking the button via pressed in getButtonState() (it should be equivalent to the justPressed used in the original). The values are still consistently different, with the avg delay from .5s points being 0.046 in Sim and 0.1 on device.
The issue is that some of the values stray pretty long way (~130ms), so that makes detecting the on-beat complicated (false misses are a big bummer in a rhythm game).
My current workaround is to add a 80ms delay on device by default and increase the buffer around it a bit. However, a fix could break the game in the future, so I’d be happy to hear if this issue is unsolvable.
Aside from that, I checked the button press read and it seems to be pretty okay — from the visible button moving to the screen redraw (gfx.clear() with a specified color), it seems to be about ~10–12 frames at 240fps recording (0.04s, see frames 296 - 308) a the button is probably actuated later than on frame 1 — so I think the readout from the button might be up to date right away at the closest update.
I tried to hit that button as fast as possible, poor Playdate
Note: My friend had an idea that it’s the difference in how I hear the audio, less bass in Playdate might actually trigger me to press the button later than the solid bass from the PC headphones. We tested this with the headphones on the Playdate and there’s still a difference.
I did a few more rounds of testing after seeing a change in the data with the headphones on, and it seems that my friend was right — it’s probably the sound being different from the playdate speaker than from the headphones.
The bass hits much less intensively from the speaker on Playdate and so it makes us press the button with a delay. With headphones on, the measured data become inconclusive after a longer session (with the example above running at 50 fps), with some deviations possibly caused by us and the song.
This probably means that I’ll need to just widen the time window for non-headphone use and test each song on headphones and the speaker with a special setting.
If I find out more, I’ll post below, but so far I’m marking this as Solved.