Skip to content

Store framerate internally as Fraction, expose via property#75

Open
nickswalker wants to merge 2 commits into
eoyilmaz:mainfrom
nickswalker:fraction-framerate
Open

Store framerate internally as Fraction, expose via property#75
nickswalker wants to merge 2 commits into
eoyilmaz:mainfrom
nickswalker:fraction-framerate

Conversation

@nickswalker

Copy link
Copy Markdown

This changeset makes tc.framerate return a Fraction instead of a str. The string representation was the source of the problem fixed with #74 (because float("47.95") != float(48000/1001). With Fraction storage that class of bug disappears. This was the core of @cubicibo's changes in #69

Timecode("29.97", ...).framerate  # before: "29.97"
Timecode("29.97", ...).framerate  # after:  Fraction(30000, 1001)

All existing input forms still work. NTSC string aliases ("23.976", "23.98", "29.97", etc.) canonicalize to the same exact fraction regardless of how they were specified.

Breaking change

Any code comparing tc.framerate to a string will break:

tc.framerate == "29.97"   # was True, now False

float(tc.framerate) and tc.framerate == other.framerate continue to work.

Performance

Fraction("29.97") costs ~1.5 µs and float(Fraction(...)) another ~1.6 µs, enough to double construction time for common string inputs. A module-level lookup table of pre-computed Fraction objects for all standard rates eliminates this:

master this PR
Timecode("24", ...) 1.88 µs 1.36 µs
Timecode("29.97", ...) 1.93 µs 1.57 µs
Timecode(Fraction(30000,1001), ...) 3.39 µs 3.78 µs

Times medians of 20k runs, Apple M series chip

Previously the framerate setter normalized all inputs to a rounded
string (e.g. Fraction(24000, 1001) → "23.98"), so tc.framerate always
returned str. The setter now stores a canonical Fraction and the
property returns it directly.

NTSC rates are canonicalized to their exact fraction (24000/1001,
30000/1001, etc.) regardless of how they were specified. The "frames"
alias (1 fps) and "ms" alias (1000 fps) are still accepted as input.

As a consequence, frames_to_tc's drop-frame period calculations are
switched from float-based rounding to exact integer arithmetic using
_int_framerate, which is more correct and avoids precision sensitivity
to the exact float representation of the framerate.

Co-authored-by: cubicibo <55701024+cubicibo@users.noreply.github.com>
Converting to Fraction is about 2x slower than the
original code path. Loading from the cache is
modestly faster, and should handle the vast majority
of usage
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant