pub struct Variables<'a> { /* private fields */ }Expand description
A bound set of variable values for one evaluation. Field order matches
VAR_NAMES; beat is the caller’s bool coerced to 0.0/1.0.
The spectrum is held by borrow, not by value (ADR-0036): the analysis
frame’s 64 bands are 256 bytes, and this bundle is built once per frame but
read once per binding. A by-value payload would put that memcpy on the
per-binding path; a slice reference keeps the whole struct at nine floats
plus a fat pointer, so it stays cheaply Copy.
Implementations§
Source§impl<'a> Variables<'a>
impl<'a> Variables<'a>
Sourcepub fn new(
bass: f32,
mid: f32,
treb: f32,
onset: f32,
beat: f32,
bar: f32,
time: f32,
tempo: f32,
novelty: f32,
) -> Self
pub fn new( bass: f32, mid: f32, treb: f32, onset: f32, beat: f32, bar: f32, time: f32, tempo: f32, novelty: f32, ) -> Self
Bind all nine variables (order matches VAR_NAMES). tempo is the
tracked BPM (0 until the tracker warms, then ~60-200 — not a 0..1
band); novelty is the experimental spectral track-change transient.
The spectrum starts empty; attach one with
with_spectrum.
Sourcepub fn with_raw(
self,
bass_raw: f32,
mid_raw: f32,
treb_raw: f32,
onset_raw: f32,
) -> Self
pub fn with_raw( self, bass_raw: f32, mid_raw: f32, treb_raw: f32, onset_raw: f32, ) -> Self
Bind the four absolute levels bass_raw/mid_raw/treb_raw/onset_raw
(ADR-0049), leaving everything else as it was.
A builder rather than four more positional arguments on
new: that constructor is already at the argument-count lint
and growing it to thirteen is how a caller silently transposes two levels.
Sourcepub fn with_beat_clock(self, beat_index: u32, time_since_beat: f32) -> Self
pub fn with_beat_clock(self, beat_index: u32, time_since_beat: f32) -> Self
Bind beat_index and time_since_beat (ADR-0050 Layer 1), leaving
everything else as it was.
beat_index arrives as the frame’s u32 and converts here: exact up to
2^24 beats, which at 200 BPM is about 1400 hours of continuous playback.
Sourcepub fn with_bar(self, beat_in_bar: u32, bar_index: u32, bar_phase: f32) -> Self
pub fn with_bar(self, beat_in_bar: u32, bar_index: u32, bar_phase: f32) -> Self
Bind beat_in_bar, bar_index and bar_phase (ADR-0050 Layer 2),
leaving everything else as it was.
These arrive already resolved: the caller has decided whether they came from the downbeat estimate or from the counter fallback, so nothing here or downstream needs to know which. That is the point of the gate living in the analyzer.
Sourcepub fn from_frame(frame: &'a AnalysisFrame, time: f32) -> Self
pub fn from_frame(frame: &'a AnalysisFrame, time: f32) -> Self
Bind every analysis variable from frame, with the clock at time.
This is the only place the frame-to-slot mapping is written. Both the
render loop and shot’s reachability probe come through here, so a tenth
variable or a reordered slot is a one-file change rather than two copies
that happen to agree. They did agree — and nothing could have told you
which one the code actually used, which is the failure this closes: a
probe binding different values than the engine would report flags about
an expression the renderer never evaluates (Plan 0041 review).
time stays an argument because it is the one variable that is not on
the frame — the renderer passes its own clock, the probe the hop position
it synthesized.
The band array rides by borrow (ADR-0036), so this costs exactly what
new plus with_spectrum cost: no
copy of the spectrum, nothing allocated, safe on the per-frame path.
Sourcepub fn with_latches(self, values: &[f32]) -> Self
pub fn with_latches(self, values: &[f32]) -> Self
Bind the reserved [latch] block from values (ADR-0137), leaving
everything else as it was.
The render layer’s latch bank calls this once per preset per frame,
before the params that read a latch. Entries past LATCH_CAP are
ignored, and a slot no latch declares keeps its 0.0 rest value — which
is what any caller that does not run a bank (a probe, a test, a
single-frame capture) sees for every latch.
Sourcepub fn with_index(self, t: f32) -> Self
pub fn with_index(self, t: f32) -> Self
Rebind the per-element index to t (the element’s normalized 0..1
position), returning a fresh binding — the caller evaluates once per
element against these (Plan 0034 Phase 4).
By value and Copy, so a per-element loop rebinds one float without
touching the borrowed spectrum or allocating.
Sourcepub fn with_vertex(self, x: f32, y: f32, rad: f32, ang: f32) -> Self
pub fn with_vertex(self, x: f32, y: f32, rad: f32, ang: f32) -> Self
Rebind the per-vertex position x, y, rad, ang, returning a fresh
binding — the caller evaluates a [per_vertex] binding once per mesh
vertex against these (Plan 0100 Phase 1).
x/y are the vertex’s uv in 0..1; rad is its distance from the
mesh centre and ang its angle there, both taken in the
aspect-corrected space of the render target (ADR-0037) so a
rad-driven figure is round on any display and does not follow the mesh
grid’s own proportions. The caller does that correction — this only
carries the four values.
By value and Copy, like with_index: a per-vertex
loop rebinds four floats without touching the borrowed spectrum or
allocating.
Sourcepub fn with_spectrum(self, spectrum: &'a [f32]) -> Self
pub fn with_spectrum(self, spectrum: &'a [f32]) -> Self
Attach the frame’s log-spaced band array, which bin(x) samples. A
borrow rather than a copy — see the type docs. Kept a separate builder so
the nine-scalar constructor stays the shape every existing caller (and
every test) already uses.
Sourcepub fn with_salt(self, salt: u32) -> Self
pub fn with_salt(self, salt: u32) -> Self
Bind the per-preset salt hash()/noise() mix in (ADR-0051).
Its own builder rather than a constructor argument because the salt is a
fact about the preset, not about the analysis frame: the render loop
builds one Variables per frame from the frame alone, then re-salts it
per preset. That is what keeps both sides of a dissolve on their own seed
while they read the same audio.
By value and Copy, like with_index — re-salting
rebinds one u32 without touching the borrowed spectrum or allocating.