helena 0.1.0

Core types and component interfaces for helena, a latent data-to-waveform generation platform.
Documentation
use std::num::NonZeroU32;

use crate::latent::Continuous;
use crate::{
    ClipDuration, Conditioning, Error, GenerationParams, GlobalLatent, Latent, LatentGenerator,
    Result, SampleRate, Seed, Tensor, TimeBase,
};

use super::*;

/// A fixed latent clock for the diagnostics' test fixtures. The diagnostics read
/// only the payload ([`FrameSeq`](crate::FrameSeq)), never the clock, so any
/// representative time base does; sharing one keeps the fixtures terse.
fn tb() -> TimeBase {
    TimeBase::new(
        SampleRate::try_from(48_000).unwrap(),
        NonZeroU32::new(480).unwrap(),
    )
}

/// A continuous latent of shape `[frames, dim]` from row-major `data`.
fn latent(shape: [usize; 2], data: Vec<f32>) -> Latent<Continuous> {
    Latent::new(
        crate::FrameSeq::new(shape[0], shape[1], data).unwrap(),
        tb(),
    )
}

/// Deterministic per-call parameters at neutral guidance — the baseline the grid
/// driver overrides only the seed of.
fn params() -> GenerationParams {
    GenerationParams::deterministic(ClipDuration::new(1.0).unwrap())
}

struct MockGenerator {
    cond_weight: f32,
    seed_weight: f32,
}

impl LatentGenerator<Continuous> for MockGenerator {
    fn generate(
        &self,
        conditioning: &Conditioning,
        params: &GenerationParams,
    ) -> Result<Latent<Continuous>> {
        let c = conditioning
            .global()
            .map(|g| g.tensor().data()[0])
            .unwrap_or(0.0);
        let s = params.seed.seed().map(|seed| seed.0).unwrap_or(0) as f32;
        let value = self.cond_weight * c + self.seed_weight * s;
        Ok(latent([1, 1], vec![value]))
    }
}

struct FailingGenerator;

impl LatentGenerator<Continuous> for FailingGenerator {
    fn generate(
        &self,
        _conditioning: &Conditioning,
        _params: &GenerationParams,
    ) -> Result<Latent<Continuous>> {
        Err(Error::validation("mock failure"))
    }
}

fn cond(value: f32) -> Conditioning {
    Conditioning::new()
        .with_global(GlobalLatent::new(Tensor::new([1, 1], vec![value]).unwrap()).unwrap())
}

fn scalar_sweep(values: &[f32]) -> Vec<Vec<Latent<Continuous>>> {
    values
        .iter()
        .map(|&v| vec![latent([1, 1], vec![v])])
        .collect()
}

mod diagnostics;
mod dispersion;
mod properties;
mod response;
mod sampling;
mod snr_loss;
mod step_gap;