Skip to main content

AnalysisFrame

Struct AnalysisFrame 

Source
pub struct AnalysisFrame {
Show 22 fields pub spectrum: [f32; 64], pub waveform: [f32; 512], pub waveform_gain: f32, pub onset: f32, pub beat: bool, pub bass: f32, pub mid: f32, pub treb: f32, pub bass_raw: f32, pub mid_raw: f32, pub treb_raw: f32, pub onset_raw: f32, pub bpm: f32, pub bar: f32, pub beat_index: u32, pub time_since_beat: f32, pub beat_in_bar: u32, pub bar_index: u32, pub bar_phase: f32, pub downbeat_confidence: f32, pub downbeat_locked: bool, pub novelty: f32,
}
Expand description

One hop’s worth of analysis.

The four headline levels are normalized (ADR-0049): bass, mid, treb and onset are each a 0..1 fraction of that signal’s own slowly-decaying recent peak, so > 0.5 means “loud for this track” rather than naming an absolute magnitude that depended on the gain staging. The absolute values remain as *_raw for looks that genuinely want them, and for harness continuity. spectrum normalizes against one peak shared by the whole array, so every ratio inside it — and therefore every bin() contrast — comes through untouched; see gain::BandNormalizer for why per-band would not.

beat flags an onset event this hop; bpm/bar come from the tempo tracker, which reads the raw onset — see gain for why the internal consumers are deliberately left on raw values. The bar-position trio comes from downbeat, and falls back to plain counters whenever its estimate is not confident (ADR-0050).

Fields§

§spectrum: [f32; 64]

Per-band energy, the whole array normalized against one shared recent peak — so every ratio inside it, and therefore every bin() contrast, comes through untouched. Not a per-band normalization: that was the draft ADR-0049 rejected, because it flattens the very shape a spectrum is for.

§waveform: [f32; 512]

The most recent WAVE_SAMPLES of the mono signal, in time order — the oscilloscope trace, not a spectrum (Plan 0100 Phase 4 / ADR-0113).

Nothing in the engine’s own vocabulary reads this: the expression grammar is scalar and reaches the band array through bin() alone (ADR-0036), and widening it to an array type is exactly what ADR-0002’s purity refuses. It is here for the one consumer that genuinely needs a waveform — the warp mesh’s wave_mode draw, which is what MilkDrop’s presets use as their light source, and which no amount of spectrum can reconstruct.

Levelled against its own recent peak (ADR-0139), like every other headline value on this struct: the whole trace is divided by one slowly-released running peak of its magnitude, so it reads -1..=1 at any fader position. That is what makes the two frontends agree — the plugin taps the decoded stream before the output volume, the standalone taps loopback after it, and only the absolute level differs between them. Dynamics within a track survive the seconds-scale release; a quiet track reads like a loud one, which is the price of cancelling a volume knob nothing else can see. The consumer still scales what it gets (MilkDrop’s wave_scale does exactly that).

waveform_gain is the divisor, so an absolute amplitude is one multiply away and a true oscilloscope stays reachable.

This is the array that made this struct big. AnalysisFrame is Copy and copied per frame, and 512 floats take it from ~340 bytes to ~2.4 kB — about 100 ns of memcpy at 60 Hz, which is why it was acceptable. It is deliberately not in Variables, which carries the band array by borrow for precisely this reason.

§waveform_gain: f32

The divisor waveform was levelled by: waveform[i] * waveform_gain is the raw amplitude the analyzer read.

0.0 while the tracked peak sits under gain::WAVE_FLOOR, where the trace is zeroed rather than amplified — so reconstructing from a silent frame gives silence rather than noise.

§onset: f32

Spectral-flux onset envelope, normalized against its recent peak.

§beat: bool

Whether a beat (onset event) fired this hop.

§bass: f32

Bass-band level (~20-250 Hz), normalized against its recent peak.

§mid: f32

Mid-band level (~250-4000 Hz), normalized against its recent peak.

§treb: f32

Treble-band level (~4-18 kHz), normalized against its recent peak.

§bass_raw: f32

Raw mean magnitude in the bass band — the pre-ADR-0049 bass, unchanged.

§mid_raw: f32

Raw mean magnitude in the mid band — the pre-ADR-0049 mid, unchanged.

§treb_raw: f32

Raw mean magnitude in the treble band — the pre-ADR-0049 treb, unchanged.

§onset_raw: f32

Raw spectral-flux envelope — the pre-ADR-0049 onset, unchanged.

§bpm: f32

Tempo estimate in BPM (hop-clock autocorrelation; 0 until warm).

§bar: f32

Beat phase in [0, 1): 0 on each beat, ramping to the next.

The name is a documented misnomer — this is beat phase, not bar phase. Too widely bound to rename (ADR-0050); bar_phase is the true quantity.

§beat_index: u32

Monotone count of onset detections since the stream started, 0 before the first (ADR-0050 Layer 1, corrected by ADR-0109). Unconditional and deterministic — no confidence gate. Not a musical period: the detector fires 1.2x-2.3x per musical beat depending on the material and wanders inside a single track, so no fixed multiplier converts this to beats.

§time_since_beat: f32

Seconds since the last onset detection; exactly 0 on a detection hop.

§beat_in_bar: u32

Which beat of the bar this is, 0..4 (ADR-0050 Layer 2). Estimated when the downbeat tracker is confident, and the fold’s own counter modulo 4 otherwise — see bar_index for what that counter is.

§bar_index: u32

Bar counter, on the same gated-or-counted basis. Monotone except across an alignment change — it is (beat count - alignment) / 4, where the beat count is the grid’s tempo-driven one, and beat_index only while the grid warms up. So the beat the estimator locks, drops back, or moves its alignment can repeat or skip a bar. Hysteresis makes that rare (a challenger must lead for three bars), and a repeated bar is a far softer failure than a wrong downbeat — but mod(bar_index, 8) will see it. The warmup handover is not a second source of it: the grid’s count carries a whole-bar offset that keeps this moving forward across it.

§bar_phase: f32

Position across the bar in [0, 1) — the true bar phase, as against bar, which is beat phase under a historical name.

§downbeat_confidence: f32

Downbeat-alignment confidence in 0..1. Diagnostics only — not a grammar variable, so authors get behavior rather than homework.

§downbeat_locked: bool

Whether the bar trio above came from the estimator rather than the counter fallback. Diagnostics only, as with the confidence.

§novelty: f32

Experimental spectral track-change novelty (Plan 0009 Phase 4): ~0 within a steady segment, spiking at a spectral boundary. Native-API only — not exposed across the C ABI.

Implementations§

Source§

impl AnalysisFrame

Source

pub fn fully_driven() -> Self

The one definition of “fully driven”: every headline level and the whole log-band array at full scale, with the beat flag set.

Two harnesses hold a differential against this frame — --report’s drive column and its step stimulus (ADR-0134), and the animation gate’s driven branch (ADR-0136). A second construction site would let them measure two different stimuli while reading as the same word, which is a disagreement no capture could show.

Three fields are deliberately not at full scale, and each for its own mechanism:

  • The four *_raw levels stay 0. The headline four are peak-normalized (ADR-0049), so 1.0 is the documented top of their range; a raw magnitude has no top to name, and any value picked for one would be a gain-staging assumption. A binding reading bass_raw sees silence here.
  • bpm stays 0, the tracker’s own not-yet-warm value. There is no “full scale” tempo.
  • bar is a phase in [0, 1), not a level, so it takes 0.5 — the middle of a beat rather than either edge, so a bar-driven binding reads a typical position instead of sitting on the wrap.

Trait Implementations§

Source§

impl Clone for AnalysisFrame

Source§

fn clone(&self) -> AnalysisFrame

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for AnalysisFrame

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for AnalysisFrame

Source§

fn default() -> Self

Returns the “default value” for a type. Read more
Source§

impl From<&AnalysisFrame> for AnalysisMetrics

Source§

fn from(frame: &AnalysisFrame) -> Self

Converts to this type from the input type.
Source§

impl Copy for AnalysisFrame

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

§

impl<T> WasmNotSend for T
where T: Send,

§

impl<T> WasmNotSendSync for T
where T: WasmNotSend + WasmNotSync,

§

impl<T> WasmNotSync for T
where T: Sync,