linebender / interpoli

Apache License 2.0
15 stars 6 forks source link

SMPTE Timecodes & Timelines, Layers and Keyframes. (Old) #21

Closed TheNachoBIT closed 2 months ago

TheNachoBIT commented 2 months ago

I'm making this a draft for now, this PR is to document the progress i've been making so far with this experiment.

This experiment can also fail. If you see any kind of flaw, please feel free to point it out.

The final goals of this (if succeeds) are:

Progress.

SMPTE Timecodes (Update 2).

SMPTE Timecodes are time units that are set like a clock: HH:MM:SS:FF (Hours, Minutes, Seconds, Frames).

For convenience, there's a macro that helps visualize this concept better in code:

tcode_hmsf!(01:23:45:01) // A timecode with Hours (h), Minutes (m), Seconds (s) and Frames (f).

~(Sadly, Rust's macros don't allow me to use ":" so i have to use ";" instead, if there's a workaround for this, please let me know)~

EDIT: I fixed it!

Timecodes can be used as a Timestamp, or as a value for a Timeline, by setting the Framerate:

tcode_hmsf_framerate!(00:01:02:56, Framerate::Fixed(20.0))

There's Framerate::Fixed(n) and Framerate::Interpolated(n). Once Timelines become a thing, fixed framerates will round up to the nearest frame when the tween is calculated, which will be useful for frame-by-frame animations. Interpolated frames on the other hand, will interpolate regardless of the framerate you're running (unless you explicitly set "hold" frames).

Timecodes with a framerate can advance and reverse by frames, seconds, minutes, hours and use Duration (Instant coming soon).

Example: Play one second frame-by-frame.

let mut time = tcode_hmsf_framerate!(00:00:00:00, Framerate::Fixed(24.0));

for i in 0..24 {
    time.next_frame();
}

println!("{:?}", time.as_string()); // Outputs "00:00:01:00 (24.0)"

Example: Add by Duration.

use std::time::Duration;

let mut time = tcode_hmsf_framerate!(00:00:00:00, Framerate::Fixed(24.0));

time.add_by_duration(Duration::from_millis(999));

println!("{:?}", time.as_string()); // Outputs "00:00:00:23 (24.0)"

Example: Sub by Duration.

use std::time::Duration;

let mut time = tcode_hmsf_framerate!(01:00:00:00, Framerate::Fixed(24.0)); // 1 hour

time.sub_by_duration(Duration::from_secs(1800));

println!("{:?}", time.as_string()); // Outputs "00:30:00:00 (24.0)" (30 minutes)

The draft repository contains more examples in form of tests inside of lib.rs.

This is all of the progress for now, for any questions, please feel free to ask :)

xorgy commented 2 months ago

Seems like a useful utility. I think it would be good to look at using ratios for framerates rather than floats; common framerates exist based on exact 1000/1001 fractions of a framerate. (i.e. 23.976 [1000/1001 × 24] vs 24)

TheNachoBIT commented 2 months ago

I use floats so the translation and compatibility between framerates like 23.679 and Durations, Instants and other values is more easier to deal with (atm). But maybe ratio-based framerates can fix other headaches in the future that i'm not aware of lol

TheNachoBIT commented 2 months ago

I think i figured out how the ratios work, once i'm available i'll give them a try :D

TheNachoBIT commented 2 months ago

I'm gonna try rebasing this, which it'll probably delete the current repo (and therefor, this PR). Wish me luck :')