Audio Analysis

rustjay-engine captures audio from the system default input and analyses it every frame. The results are available in EngineState::audio from build_uniforms() and prepare().

The audio state

#![allow(unused)]
fn main() {
pub struct AudioState {
    pub volume:      f32,       // RMS loudness, normalised [0, 1]
    pub fft:         [f32; 8],  // 8-band spectrum, [0, 1] each
    pub beat_pulse:  bool,      // true on beat onset this frame
    pub bpm:         f32,       // estimated BPM
    pub beat_phase:  f32,       // position within current beat [0, 1)
}
}

Volume

volume tracks the RMS loudness of the current audio frame, normalised to [0, 1]. It responds quickly — useful for direct amplitude-reactive effects.

FFT bands

fft splits the audio spectrum into 8 bands from bass to treble. Band 0 captures the lowest frequencies (sub-bass / kick drum energy), band 7 captures the highest (hi-hat / air).

#![allow(unused)]
fn main() {
let bass   = engine.audio.fft[0]; // kick, sub-bass
let mid    = engine.audio.fft[3]; // midrange, snare
let treble = engine.audio.fft[7]; // hi-hat, brightness
}

All band values are normalised to [0, 1].

Beat detection

beat_pulse is true for exactly one frame when a beat onset is detected. Use it to trigger instantaneous events:

#![allow(unused)]
fn main() {
fn build_uniforms(&self, s: &MyState, engine: &EngineState) -> MyUniforms {
    let flash = if engine.audio.beat_pulse { 1.0_f32 } else { 0.0_f32 };
    // fade flash out in the shader using a time uniform
    MyUniforms { flash, .. }
}
}

Beat phase

beat_phase is a sawtooth [0, 1) that resets to 0 on each detected beat. It's useful for smooth beat-locked animations.

#![allow(unused)]
fn main() {
let phase = engine.audio.beat_phase; // ramps 0→1 between beats
}

Using audio in your effect

Direct audio reactivity

Read FFT bands or volume directly in build_uniforms():

#![allow(unused)]
fn main() {
fn build_uniforms(&self, s: &MyState, engine: &EngineState) -> MyUniforms {
    let bass = engine.audio.fft[0];
    MyUniforms {
        displacement: s.displacement_amount * bass,
        brightness:   0.5 + engine.audio.volume * 0.5,
        // ...
    }
}
}

Via the routing matrix

For a more flexible setup — letting the user choose which FFT band drives which parameter at runtime — use the Routing Matrix. Routing contributions are already included when you call engine.get_param().

Tap tempo

The Audio tab has a tap-tempo button. The user can also tap Shift+T on the output window. Tap tempo overrides the audio BPM estimate but is itself overridden by Ableton Link or ProDJ Link if those sources are active.

For tempo-reactive effects, always use engine.effective_bpm() rather than engine.audio.bpm — it accounts for whichever source is active. See Tempo Sync.