use serde::{Deserialize, Serialize};
use crate::error::{Error, Result};
use crate::latent::{Conditioning, Latent, LatentKind, Metadata};
use crate::signal::Pcm;
use crate::tensor::Tensor;
use crate::time::TimeBase;
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
pub struct SourceBatch {
items: Vec<Tensor>,
metadata: Metadata,
}
impl SourceBatch {
pub fn new(items: Vec<Tensor>) -> Self {
Self {
items,
metadata: Metadata::default(),
}
}
pub fn with_metadata(mut self, metadata: Metadata) -> Self {
self.metadata = metadata;
self
}
pub fn items(&self) -> &[Tensor] {
&self.items
}
pub fn metadata(&self) -> &Metadata {
&self.metadata
}
pub fn len(&self) -> usize {
self.items.len()
}
pub fn is_empty(&self) -> bool {
self.items.is_empty()
}
}
pub trait SourceEncoder {
fn encode(&self, batch: &SourceBatch) -> Result<Conditioning>;
}
impl<E: SourceEncoder + ?Sized> SourceEncoder for Box<E> {
fn encode(&self, batch: &SourceBatch) -> Result<Conditioning> {
(**self).encode(batch)
}
}
pub trait Clocked {
fn time_base(&self) -> TimeBase;
}
pub trait AudioEncoder<K: LatentKind>: Clocked {
fn encode(&self, pcm: &Pcm) -> Result<Latent<K>>;
}
pub trait AudioDecoder<K: LatentKind>: Clocked {
fn decode(&self, latent: &Latent<K>) -> Result<Pcm>;
}
pub trait AudioCodec<K: LatentKind>: AudioEncoder<K> + AudioDecoder<K> {}
impl<K: LatentKind, C: AudioEncoder<K> + AudioDecoder<K> + ?Sized> AudioCodec<K> for C {}
pub trait LatentGenerator<K: LatentKind> {
fn generate(&self, cond: &Conditioning, params: &GenerationParams) -> Result<Latent<K>>;
}
impl<K: LatentKind, G: LatentGenerator<K> + ?Sized> LatentGenerator<K> for Box<G> {
fn generate(&self, cond: &Conditioning, params: &GenerationParams) -> Result<Latent<K>> {
(**self).generate(cond, params)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(transparent)]
pub struct Seed(pub u64);
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
#[serde(try_from = "f32", into = "f32")]
pub struct Temperature(f32);
impl Temperature {
pub fn new(value: f32) -> Result<Self> {
if value.is_finite() && value > 0.0 {
Ok(Self(value))
} else {
Err(Error::validation(format!(
"temperature must be finite and positive, got {value}"
)))
}
}
pub fn get(self) -> f32 {
self.0
}
}
impl TryFrom<f32> for Temperature {
type Error = Error;
fn try_from(value: f32) -> Result<Self> {
Self::new(value)
}
}
impl From<Temperature> for f32 {
fn from(t: Temperature) -> f32 {
t.get()
}
}
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
#[serde(try_from = "f32", into = "f32")]
pub struct GuidanceScale(f32);
impl GuidanceScale {
pub const NEUTRAL: GuidanceScale = GuidanceScale(1.0);
pub fn new(value: f32) -> Result<Self> {
if value.is_finite() && value >= 0.0 {
Ok(Self(value))
} else {
Err(Error::validation(format!(
"guidance scale must be finite and non-negative, got {value}"
)))
}
}
pub fn get(self) -> f32 {
self.0
}
pub fn is_neutral(self) -> bool {
self.0 == 1.0
}
}
impl TryFrom<f32> for GuidanceScale {
type Error = Error;
fn try_from(value: f32) -> Result<Self> {
Self::new(value)
}
}
impl From<GuidanceScale> for f32 {
fn from(g: GuidanceScale) -> f32 {
g.get()
}
}
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
#[serde(try_from = "f32", into = "f32")]
pub struct ClipDuration(f32);
impl ClipDuration {
pub fn new(seconds: f32) -> Result<Self> {
if seconds.is_finite() && seconds > 0.0 {
Ok(Self(seconds))
} else {
Err(Error::validation(format!(
"clip duration must be finite and positive, got {seconds}"
)))
}
}
pub fn seconds(self) -> f32 {
self.0
}
}
impl TryFrom<f32> for ClipDuration {
type Error = Error;
fn try_from(seconds: f32) -> Result<Self> {
Self::new(seconds)
}
}
impl From<ClipDuration> for f32 {
fn from(d: ClipDuration) -> f32 {
d.seconds()
}
}
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum SeedPolicy {
Deterministic,
Seeded {
seed: Seed,
temperature: Temperature,
},
Entropy {
temperature: Temperature,
},
}
impl SeedPolicy {
pub fn replayable(&self) -> bool {
!matches!(self, SeedPolicy::Entropy { .. })
}
pub fn temperature(&self) -> Option<Temperature> {
match self {
SeedPolicy::Deterministic => None,
SeedPolicy::Seeded { temperature, .. } | SeedPolicy::Entropy { temperature } => {
Some(*temperature)
}
}
}
pub fn seed(&self) -> Option<Seed> {
match self {
SeedPolicy::Seeded { seed, .. } => Some(*seed),
_ => None,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
pub struct GenerationParams {
pub duration: ClipDuration,
pub seed: SeedPolicy,
pub guidance: GuidanceScale,
}
impl GenerationParams {
pub fn deterministic(duration: ClipDuration) -> Self {
Self {
duration,
seed: SeedPolicy::Deterministic,
guidance: GuidanceScale::NEUTRAL,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::latent::{Continuous, FrameSeq};
use crate::time::SampleRate;
use std::num::NonZeroU32;
#[test]
fn newtypes_reject_illegal_values() {
assert!(Temperature::new(0.0).is_err());
assert!(Temperature::new(-1.0).is_err());
assert!(Temperature::new(f32::NAN).is_err());
assert!(Temperature::new(0.8).is_ok());
assert!(GuidanceScale::new(-0.1).is_err());
assert!(GuidanceScale::new(f32::INFINITY).is_err());
assert!(GuidanceScale::new(0.0).is_ok());
assert!(GuidanceScale::NEUTRAL.is_neutral());
assert!(ClipDuration::new(0.0).is_err());
assert!(ClipDuration::new(12.5).is_ok());
}
#[test]
fn seed_policy_states_are_exactly_the_legal_ones() {
let det = SeedPolicy::Deterministic;
assert!(det.replayable());
assert_eq!(det.temperature(), None);
let seeded = SeedPolicy::Seeded {
seed: Seed(7),
temperature: Temperature::new(1.0).unwrap(),
};
assert!(seeded.replayable());
assert_eq!(seeded.seed(), Some(Seed(7)));
let entropy = SeedPolicy::Entropy {
temperature: Temperature::new(0.5).unwrap(),
};
assert!(!entropy.replayable());
assert!(
serde_json::from_str::<SeedPolicy>(r#"{"seeded":{"seed":1,"temperature":0.0}}"#)
.is_err()
);
}
#[test]
fn boxed_dyn_generator_forwards_to_inner() {
struct Echo(Latent<Continuous>);
impl LatentGenerator<Continuous> for Echo {
fn generate(
&self,
_cond: &Conditioning,
_params: &GenerationParams,
) -> Result<Latent<Continuous>> {
Ok(self.0.clone())
}
}
let tb = crate::time::TimeBase::new(
SampleRate::try_from(48_000).unwrap(),
NonZeroU32::new(480).unwrap(),
);
let latent = Latent::new(FrameSeq::new(1, 2, vec![0.25, -0.5]).unwrap(), tb);
let boxed: Box<dyn LatentGenerator<Continuous>> = Box::new(Echo(latent.clone()));
let params = GenerationParams::deterministic(ClipDuration::new(1.0).unwrap());
let out = boxed.generate(&Conditioning::default(), ¶ms).unwrap();
assert_eq!(out, latent);
}
}