simfile.timing.engine

Module Contents

Classes

SongTime

A floating-point time value, denoting a temporal position in a simfile.

EventTag

Types of timing events.

TimingEngine

Convert song time to beats and vice-versa.

class simfile.timing.engine.SongTime

Bases: float

A floating-point time value, denoting a temporal position in a simfile.

class simfile.timing.engine.EventTag

Bases: enum.IntEnum

Types of timing events.

The order of these values determines how multiple events on the same beat will be sorted: for example, delays must occur before stops in order to correctly time notes on a beat with both a delay and a stop.

Warps, delays, and stops have a corresponding “end” type that TimingEngine uses to simplify the beat/time conversion logic. These can be used to disambiguate the time at a given beat (for stops & delays) or the beat at a given time (for warps).

WARP = 0
WARP_END = 1
BPM = 2
DELAY = 3
DELAY_END = 4
STOP = 5
STOP_END = 6
class simfile.timing.engine.TimingEngine(timing_data: simfile.timing.TimingData)

Convert song time to beats and vice-versa.

Under the hood, this class arranges timing events chronologically, determines the song time and BPM at each event, then extrapolates from those calculated values for each bpm_at() / time_at() / beat_at() call.

timing_data :simfile.timing.TimingData
bpm_at(self, beat: simfile.timing.Beat) → decimal.Decimal

Find the song’s BPM at a given beat.

Neither warps, stops, nor delays affect the output of this method: warps are not considered “infinite BPM”, nor are pauses considered “zero BPM”.

hittable(self, beat: simfile.timing.Beat) → bool

Determine if a note on the given beat would be hittable.

A note is considered “unhittable” if and only if:

  • It takes place inside a warp segment (inclusive of the warp’s start, exclusive of the warp’s end).

  • It doesn’t coincide with a stop or delay.

StepMania internally converts unhittable notes to fake notes so that the player’s score isn’t affected by them.

time_at(self, beat: simfile.timing.Beat, event_tag: EventTag = EventTag.STOP)SongTime

Determine the song time at a given beat.

On most beats, the event_tag parameter is inconsequential. The only time it matters is when stops or delays are involved:

  • On stops, providing a value of EventTag.STOP or lower will return the time at which the stop is reached, whereas providing EventTag.STOP_END will return the time when the stop ends.

  • On delays, providing a value of EventTag.DELAY or lower will return the time at which the delay is reached, whereas providing EventTag.DELAY_END or later will return the time when the delay ends.

The default value of EventTag.STOP effectively matches the time at which a note on the given beat must be hit (assuming such a note is hittable()).

beat_at(self, time: SongTimeOrFloat, event_tag: EventTag = EventTag.STOP)simfile.timing.Beat

Determine the beat at a given time in the song.

At most times, the event_tag parameter is inconsequential. The only time it matters is when the time lands exactly on a warp segment:

  • Providing EventTag.WARP will return the beat where the warp starts.

  • Providing EventTag.WARP_END or later will return the beat where the warp ends (or is interrupted by a stop or delay).

Keep in mind that this situation is floating-point precise, so it’s unlikely for the event_tag to ever make a difference.