Skip to main content

Param

Struct Param 

Source
#[repr(C)]
pub struct Param { pub current: f32, pub target: f32, pub step: f32, }
Expand description

A single smoothed parameter.

Provides sample-accurate parameter automation with linear ramping. Parameters smoothly transition from current to target over a specified number of samples, preventing audio clicks and zipper noise.

§Real-Time Safety

  • ✅ No allocation
  • ✅ No locks
  • ✅ Bounded execution time
  • ✅ Safe to use in audio thread

§Example

use aether_core::param::Param;

let mut gain = Param::new(0.5);

// Schedule ramp to 1.0 over 480 samples (10ms @ 48kHz)
gain.set_target(1.0, 480);

// Tick through samples
for _ in 0..480 {
    let value = gain.current;
    // Use value for processing...
    gain.tick();
}

// Close enough to 1.0 (floating point precision)
assert!((gain.current - 1.0).abs() < 0.0001);

§Performance

  • Fast path when not ramping (step == 0.0)
  • SIMD-friendly linear interpolation
  • Automatic overshoot clamping

§See Also

Fields§

§current: f32§target: f32§step: f32

Per-sample increment. Set by set_target.

Implementations§

Source§

impl Param

Source

pub fn new(value: f32) -> Self

Creates a new parameter with the given initial value.

The parameter starts at the specified value with no ramping (current == target, step == 0.0).

§Arguments
  • value - Initial parameter value
§Example
use aether_core::param::Param;

let gain = Param::new(0.75);
assert_eq!(gain.current, 0.75);
assert_eq!(gain.target, 0.75);
assert_eq!(gain.step, 0.0);
Source

pub fn set_target(&mut self, target: f32, ramp_samples: u32)

Schedule a ramp to target over ramp_samples samples.

Sets up linear interpolation from current value to target value. Call from the control thread before pushing an UpdateParam command.

§Arguments
  • target - Target value to ramp towards
  • ramp_samples - Number of samples for the ramp (0 = instant)
§Example
use aether_core::param::Param;

let mut cutoff = Param::new(1000.0);

// Ramp to 5000 Hz over 960 samples (20ms @ 48kHz)
cutoff.set_target(5000.0, 960);

// After 480 samples, we're halfway
for _ in 0..480 {
    cutoff.tick();
}
assert!((cutoff.current - 3000.0).abs() < 1.0);

// After 960 samples total, we've reached the target
for _ in 0..480 {
    cutoff.tick();
}
assert!((cutoff.current - 5000.0).abs() < 0.01);
§Instant Changes
use aether_core::param::Param;

let mut gain = Param::new(0.5);

// Instant change (0 samples)
gain.set_target(1.0, 0);
assert_eq!(gain.current, 1.0);
assert_eq!(gain.step, 0.0);
Source

pub fn tick(&mut self)

Advance by one sample. Call once per sample in the RT loop.

Updates current by adding step. When the target is reached, automatically stops ramping by setting step to 0.0.

§Example
use aether_core::param::Param;

let mut gain = Param::new(0.0);
gain.set_target(1.0, 100);

// Tick through 100 samples
for i in 0..100 {
    gain.tick();
}

// Reached target value
assert!((gain.current - 1.0).abs() < 0.0001);
§Performance

This function is highly optimized for the audio thread:

  • Inlined for zero call overhead
  • Branch-free when not ramping
  • Automatic overshoot clamping
Source

pub fn fill_buffer(&mut self, out: &mut [f32])

Advance by a full buffer, returning per-sample values into out.

Efficiently fills a buffer with parameter values, advancing the ramp for each sample. Uses a fast path when the parameter is stable (not ramping).

§Arguments
  • out - Output buffer to fill with parameter values
§Example
use aether_core::param::Param;
use aether_core::BUFFER_SIZE;

let mut cutoff = Param::new(1000.0);
cutoff.set_target(2000.0, BUFFER_SIZE as u32);

let mut buffer = [0.0f32; BUFFER_SIZE];
cutoff.fill_buffer(&mut buffer);

// First sample is near 1000, last sample is near 2000
assert!((buffer[0] - 1000.0).abs() < 50.0);
assert!((buffer[BUFFER_SIZE-1] - 2000.0).abs() < 50.0);
§Performance

This function has two paths:

  • Fast path (step == 0.0): Fills buffer with single value (SIMD-friendly)
  • Ramp path (step != 0.0): Advances sample-by-sample

The fast path is taken 90%+ of the time in typical usage.

§Use Case

Use this when you need per-sample parameter values for modulation:

use aether_core::param::Param;
use aether_core::BUFFER_SIZE;

let mut gain = Param::new(0.5);
let mut gain_buffer = [0.0f32; BUFFER_SIZE];
let input = [1.0f32; BUFFER_SIZE];
let mut output = [0.0f32; BUFFER_SIZE];

// Fill gain buffer
gain.fill_buffer(&mut gain_buffer);

// Apply per-sample gain
for i in 0..BUFFER_SIZE {
    output[i] = input[i] * gain_buffer[i];
}

Trait Implementations§

Source§

impl Clone for Param

Source§

fn clone(&self) -> Param

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 Param

Source§

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

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

impl Copy for Param

Auto Trait Implementations§

§

impl Freeze for Param

§

impl RefUnwindSafe for Param

§

impl Send for Param

§

impl Sync for Param

§

impl Unpin for Param

§

impl UnsafeUnpin for Param

§

impl UnwindSafe for Param

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> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
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.