cutan.impacts.clip¶
One impact clip, end to end: spec -> scene -> ground truth -> (video) -> files.
ImpactClipSpec is the whole description of a clip as flat, JSON-able
data — it is written verbatim into the sidecar, so any clip can be regenerated
from its own truth.json. plan_impact_clip() turns it into the scene an
animation would have (props + tweens, a normal an Shot) without touching
disk; write_impact_clip() compiles it, extracts the ground truth, renders
the video (optional — the truth and keypoints need no browser), and writes:
>>> plan = plan_impact_clip(ImpactClipSpec(beats=4, tempo=120))
>>> [e.t_grid for e in plan.events] # intended
[0.5, 1.0, 1.5, 2.0]
>>> [round(e.t_impact - e.t_grid, 3) for e in plan.events] # executed: humanised
[0.003, 0.013, -0.005, 0.006]
>>> len(plan.frames)
75
Module Attributes
Seconds after the last grid beat before the clip ends. |
|
Default humanisation (seconds, standard deviation). |
|
Samples per second of the dense trajectory in |
|
an accelerando with accents and human, slightly drifting timing. |
Functions
|
The cartesian product of the given axes over |
|
Resolve |
|
Write one clip into |
|
Write every clip in |
Classes
|
Everything that determines a clip. |
|
A clip before it touches disk: events, motion, camera, and the Scene IR. |
Exceptions
A clip spec that cannot describe a clip. |
- cutan.impacts.clip.BENCHMARK_SPEC = ImpactClipSpec(object='stick', kind='surface', tempo=((0.0, 96.0), (24.0, 132.0)), beats=24, subdivision=1, pattern=(1.0, 0.6, 0.8, 0.6), lead_in=0.5, tail=0.5, jitter_sd=0.012, jitter_rho=0.3, jitter_bias=0.0, rise=0.18, fall=0.18, brake=0.03, rise_sd=0.0, fall_sd=0.0, brake_sd=0.0, arc_radius=None, show_surface=None, fps=30.0, exposure=0.0, exposure_samples=None, timestamp_jitter_sd=0.0, timestamp_noise_sd=0.0, phase=0.0, timestamps='nominal', width=640, height=360, trajectory_hz=1000.0, seed=0)¶
an accelerando with accents and human, slightly drifting timing. What
impact_set_specs()varies the camera and the object over.- Type:
A harder default for scoring estimators
- cutan.impacts.clip.DEFAULT_JITTER_SD: float = 0.008¶
Default humanisation (seconds, standard deviation). See
ImpactClipSpec.
- cutan.impacts.clip.DEFAULT_TAIL: float = 0.5¶
Seconds after the last grid beat before the clip ends.
- cutan.impacts.clip.DEFAULT_TRAJECTORY_HZ: float = 1000.0¶
Samples per second of the dense trajectory in
trajectory.csv.
- class cutan.impacts.clip.ImpactClipSpec(object='stick', kind='surface', tempo=100.0, beats=16, subdivision=1, pattern=(1.0,), lead_in=0.5, tail=0.5, jitter_sd=0.008, jitter_rho=0.0, jitter_bias=0.0, rise=0.18, fall=0.18, brake=0.03, rise_sd=0.0, fall_sd=0.0, brake_sd=0.0, arc_radius=None, show_surface=None, fps=30.0, exposure=0.0, exposure_samples=None, timestamp_jitter_sd=0.0, timestamp_noise_sd=0.0, phase=0.0, timestamps='nominal', width=640, height=360, trajectory_hz=1000.0, seed=0)[source]¶
Bases:
objectEverything that determines a clip. Defaults: a stick hitting a table at 100 BPM.
Performance:
tempo(a bpm, or[(beat, bpm), ...]for a tempo change),beats,subdivision,pattern(per-step stroke heights,0= rest),lead_in,tail, and the humanisationjitter_sd/jitter_rho/jitter_bias(seconds; seecutan.impacts.performance.gaussian_humanizer()). Humanised by default (jitter_sd=DEFAULT_JITTER_SD): on a perfect grid every impact of a round tempo lands exactly on a frame at common rates, which is the one case a sub-frame estimator cannot be scored on. Set it to 0 for a metronome.Motion:
object("stick"or"ball"),kind("surface"or"air"), the stroke timingsrise/fall/brake, andshow_surface(None: drawn for surface impacts only). Stroke-shape variability (cutan#27):rise_sd/fall_sd/brake_sd(seconds) draw each stroke’s own timings around those means from the seed’s stroke stream, never belowMIN_TIMING_FRACTIONof the mean;truth.jsonrecords each event’s actualrise,fallandbrake.arc_radius(scene px, the ball only) swings the ball on a circle about a pivot that far above its contact point, instead of a straight fall: the contact is the arc’s lowest point andimpact_xyis where it lands, as before.Camera (
an.frame_clock.FrameClock):fps,exposure,exposure_samples,timestamp_jitter_sd(when frames are really taken),timestamp_noise_sd(noise on the reported timestamp only),phase,timestamps.seeddrives two independent streams — the performance’s and the camera’s — so clips that differ only in camera settings share the exact same performance.- property clip_id: str¶
A readable, deterministic directory name.
>>> ImpactClipSpec().clip_id[:-8] 'stick-surface-30fps-e0-' >>> ImpactClipSpec().clip_id == ImpactClipSpec().clip_id True
- class cutan.impacts.clip.ImpactPlan(spec, events, obj, stroke, frames, scene)[source]¶
Bases:
objectA clip before it touches disk: events, motion, camera, and the Scene IR.
- exception cutan.impacts.clip.ImpactSpecError[source]¶
Bases:
ValueErrorA clip spec that cannot describe a clip.
- cutan.impacts.clip.impact_set_specs(*, base=ImpactClipSpec(object='stick', kind='surface', tempo=((0.0, 96.0), (24.0, 132.0)), beats=24, subdivision=1, pattern=(1.0, 0.6, 0.8, 0.6), lead_in=0.5, tail=0.5, jitter_sd=0.012, jitter_rho=0.3, jitter_bias=0.0, rise=0.18, fall=0.18, brake=0.03, rise_sd=0.0, fall_sd=0.0, brake_sd=0.0, arc_radius=None, show_surface=None, fps=30.0, exposure=0.0, exposure_samples=None, timestamp_jitter_sd=0.0, timestamp_noise_sd=0.0, phase=0.0, timestamps='nominal', width=640, height=360, trajectory_hz=1000.0, seed=0), objects=('stick', 'ball'), kinds=('surface', 'air'), fps=(24, 30, 60), exposures=(0.0, 0.5), timestamp_jitter_sds=(0.0,), seeds=(0,))[source]¶
The cartesian product of the given axes over
base.>>> len(impact_set_specs()) 24 >>> {s.seed for s in impact_set_specs(seeds=(0, 1), fps=(30,))} {0, 1}- Return type:
- cutan.impacts.clip.plan_impact_clip(spec)[source]¶
Resolve
specinto events, a stroke, frames and a Scene IR. No I/O.- Return type:
- cutan.impacts.clip.write_impact_clip(spec, out_dir, *, render=True, clip_dir=None)[source]¶
Write one clip into
out_dir / (clip_dir or spec.clip_id); return that dir.With
render=Falseeverything butclip.mp4is written, and no browser is needed: the keypoints and the truth come from the compiled document, not from the pixels.- Return type:
- cutan.impacts.clip.write_impact_set(out_dir, specs=None, *, render=True, progress=None)[source]¶
Write every clip in
specs(default:impact_set_specs()) plusindex.json.progress, if given, is called with(i, n, clip_dir)after each clip.- Return type: