How can I determine how on-beat an input is in Unity? (with no delay)

I’m currently developing a game with rhythm-based elements. I want the player to be encouraged to press a button on-beat with the music, and based on how close it was to the beat, I would return a float between 0 and 1 (1 being perfectly on beat, 0 being smack in the middle between two beats). I’ve already written a function to calculate this using the getTimelinePosition(out int currentPosition) function of the music EventInstance, however there is a variable delay of a few milliseconds, which I have not been able to address. I’ve been looking for external tools that would sync with FMOD Studio and give me more precise timeline tracking capabilities, but to no avail. I’m sure other rhythm game developers have approached this problem in the past, so I would be grateful if someone could assist me in finding a solution. Thank you for your consideration, and have a wonderful day! :smiley:

Hi,

An option may be using our Timeline Callbacks (FMOD Engine | Studio API Reference - FMOD_STUDIO_EVENT_CALLBACK_TIMELINE_BEAT) we have a scripting example implementing this in Unity here: Unity Integration | Scripting Examples - Timeline Callbacks.
Hope this helps!

Hey, Connor. Thanks for getting back to me! :smiley:

While I appreciate your suggestion on implementing the Timeline Beat Callbacks, that doesn’t quite solve my problem on it’s own, unless I’m not seeing how to implement it properly. I need to be able to determine the current timeline position (in seconds/milliseconds) on any given frame in order to calculate how close I am to the beat, and the Timeline Beat callback only triggers directly on the downbeat, not in-between, so it can’t update the timeline position value until the beat value is updated.

Furthermore, it servers as a sense of confusion. In my audio manager’s Update() function, I have an if statement to determine if the timelineInfo’s beat value has been updated. If so, I write to the debug console a statement containing the current timeline position of the piece, as seen through both timelineInfo.currentPosition and musicEventInstance.getTimelinePosition(out int currentPosition). While the former is always perfectly accurate, the latter has a variable delay of up to a few milliseconds in either direction. This variability still exists when called in the FixedUpdate().

This means if I call my previously described function to determine how on-beat an action is, and I call it the second I determine a difference in the Timeline Beat Callback’s current beat value, and I call my function (using musicEventInstance.GetTimelinePosition(), the only method that can be called each any time) to reference the current timeline position, it means it’s never guaranteed to recognize the current frame as perfectly on beat, even though I’m calling it the next possible frame I can after determining the current beat has changed, according to the ever reliable Timeline Beat Callback.

I’m looking for a solution to either avoid this variable imprecision, or at least determine which of my available options is most consistent for me to base my system around. I’m sure that other developers of well-respected rhythm games have implemented such systems to determine the precise accuracy of a beat-timed input using FMOD, and I’m simply trying to figure that out for myself and my team’s project. Your assistance is greatly appreciated, and I hope to hear back from you soon. Thank you so much, and have a wonderful day!

2 Likes

Thank you for the detailed explanation.

An option may be to add markers for the off beats which will trigger the FMOD Engine | Studio API Reference - FMOD_STUDIO_TIMELINE_MARKER_PROPERTIES, which also has the position property.

Correct, the event timeline position is based on the studio update period of 20ms. You could try improve this update time by reducing the FMOD Engine | Core API Reference - System::setDSPBufferSize which can be set in the FMOD integration settings:

.

There is also the option of using the FMOD Engine | Core API Reference - ChannelControl::getDSPClock. A user has created a created a script using the DSP Clock here: Perfect Beat Tracking in Unity? - #28 by bloo_regard_q_kazoo.

Hope this helps!

Thank you for getting back to me with some suggestions, your assistance truly means the world! I’ll try implementing all of them, and get back to you in a day or two with my results, some visual demonstrations (and scripts to back them up), as well as let you know if I still require further support! :smiley:

1 Like