simfile.timing.engine ===================== .. py:module:: simfile.timing.engine Classes ------- .. autoapisummary:: simfile.timing.engine.SongTime simfile.timing.engine.EventTag simfile.timing.engine.TimingEngine Module Contents --------------- .. py:class:: SongTime Bases: :py:obj:`float` A floating-point time value, denoting a temporal position in a simfile. .. py:class:: EventTag Bases: :py:obj:`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, stops, and fakes have a corresponding "end" type that :class:`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). .. py:attribute:: FAKE :value: -2 .. py:attribute:: FAKE_END :value: -1 .. py:attribute:: WARP :value: 0 .. py:attribute:: WARP_END :value: 1 .. py:attribute:: BPM :value: 2 .. py:attribute:: DELAY :value: 3 .. py:attribute:: DELAY_END :value: 4 .. py:attribute:: STOP :value: 5 .. py:attribute:: STOP_END :value: 6 .. py:class:: 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 :meth:`bpm_at` / :meth:`time_at` / :meth:`beat_at` call. .. py:attribute:: timing_data :type: simfile.timing.TimingData .. py:method:: bpm_at(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". .. py:method:: hittable(beat: simfile.timing.Beat) -> bool Determine if a note on the given beat would be hittable. A beat is considered "unhittable" only if it's inside a warp or fake segment (including the segment's start beat, excluding its end beat) and it doesn't coincide with a stop or delay. Note that there is also a fake *note type* (``F`` in note data) that this function is unaware of. Consider using the :func:`~.time_chart` function to handle both fake regions and note types. .. py:method:: time_at(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 :data:`EventTag.STOP` or lower will return the time at which the stop is reached, whereas providing :data:`EventTag.STOP_END` will return the time when the stop ends. * On delays, providing a value of :data:`EventTag.DELAY` or lower will return the time at which the delay is reached, whereas providing :data:`EventTag.DELAY_END` or higher will return the time when the delay ends. The default value of :data:`EventTag.STOP` effectively matches the time at which a note on the given beat must be hit (assuming such a note is :meth:`hittable`). .. py:method:: beat_at(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 :data:`EventTag.WARP` or lower will return the beat where the warp starts. * Providing :data:`EventTag.WARP_END` or higher will return the beat where the warp ends (or is interrupted by a stop or delay). Note that the above scenario is floating-point precise. It will likely require a song time obtained from :meth:`~.time_at` in order for the event tag to make a difference.