use std::{ ops::{Add, Div, Mul, Neg, Rem, Sub}, time::Duration, }; use crate::{Easing, Tweenable, info::Info, modulator::ModulatorId}; /// A value that a parameter can be linked to. #[derive(Debug, Clone, Copy, PartialEq)] pub enum Value { /// A fixed value. Fixed(T), /// The value of a [`modulator`](crate::modulator). FromModulator { /// The modulator to link to. id: ModulatorId, /// How the modulator's value should be converted to the parameter's value. mapping: Mapping, }, /// The distance of the current spatial track to a listener. FromListenerDistance(Mapping), } impl Value { /// Creates a `Value::FromModulator` from a modulator ID or handle. #[must_use] pub fn from_modulator(id: impl Into, mapping: Mapping) -> Self { Self::FromModulator { id: id.into(), mapping, } } /// Converts a `Value` to a `Value`. #[must_use = "This method returns a new Value and does not mutate the original."] pub fn to_>(self) -> Value { match self { Value::Fixed(value) => Value::Fixed(value.into()), Value::FromModulator { id, mapping } => Value::FromModulator { id, mapping: mapping.to_(), }, Value::FromListenerDistance(mapping) => Value::FromListenerDistance(mapping.to_()), } } } impl Value where T: Tweenable, { pub(crate) fn raw_value(self, info: &Info) -> Option { match self { Value::Fixed(value) => Some(value), Value::FromModulator { id, mapping } => { info.modulator_value(id).map(|value| mapping.map(value)) } Value::FromListenerDistance(mapping) => info .listener_distance() .map(|value| mapping.map(value.into())), } } } impl From for Value { fn from(value: f32) -> Self { Self::Fixed(value) } } impl From for Value { fn from(value: f64) -> Self { Self::Fixed(value) } } impl From for Value> where T: Into>, { fn from(value: T) -> Self { Self::Fixed(value.into()) } } impl From for Value> where T: Into>, { fn from(value: T) -> Self { Self::Fixed(value.into()) } } impl From for Value { fn from(value: Duration) -> Self { Self::Fixed(value) } } impl Default for Value { fn default() -> Self { Self::Fixed(T::default()) } } impl Add for Value where T: Add, Rhs: Copy, { type Output = Self; fn add(self, rhs: Rhs) -> Self::Output { match self { Value::Fixed(value) => Self::Fixed(value + rhs), Value::FromModulator { id, mapping } => Value::FromModulator { id, mapping: mapping.add_output(rhs), }, Value::FromListenerDistance(mapping) => { Value::FromListenerDistance(mapping.add_output(rhs)) } } } } impl Sub for Value where T: Sub, Rhs: Copy, { type Output = Self; fn sub(self, rhs: Rhs) -> Self::Output { match self { Value::Fixed(value) => Self::Fixed(value - rhs), Value::FromModulator { id, mapping } => Value::FromModulator { id, mapping: mapping.sub_output(rhs), }, Value::FromListenerDistance(mapping) => { Value::FromListenerDistance(mapping.sub_output(rhs)) } } } } impl Mul for Value where T: Mul, Rhs: Copy, { type Output = Self; fn mul(self, rhs: Rhs) -> Self::Output { match self { Value::Fixed(value) => Self::Fixed(value * rhs), Value::FromModulator { id, mapping } => Value::FromModulator { id, mapping: mapping.mul_output(rhs), }, Value::FromListenerDistance(mapping) => { Value::FromListenerDistance(mapping.mul_output(rhs)) } } } } impl Div for Value where T: Div, Rhs: Copy, { type Output = Self; fn div(self, rhs: Rhs) -> Self::Output { match self { Value::Fixed(value) => Self::Fixed(value / rhs), Value::FromModulator { id, mapping } => Value::FromModulator { id, mapping: mapping.div_output(rhs), }, Value::FromListenerDistance(mapping) => { Value::FromListenerDistance(mapping.div_output(rhs)) } } } } impl Rem for Value where T: Rem, Rhs: Copy, { type Output = Self; fn rem(self, rhs: Rhs) -> Self::Output { match self { Value::Fixed(value) => Self::Fixed(value % rhs), Value::FromModulator { id, mapping } => Value::FromModulator { id, mapping: mapping.rem_output(rhs), }, Value::FromListenerDistance(mapping) => { Value::FromListenerDistance(mapping.rem_output(rhs)) } } } } impl Neg for Value where T: Neg, { type Output = Self; fn neg(self) -> Self::Output { match self { Value::Fixed(value) => Self::Fixed(-value), Value::FromModulator { id, mapping } => Value::FromModulator { id, mapping: mapping.neg_output(), }, Value::FromListenerDistance(mapping) => { Value::FromListenerDistance(mapping.neg_output()) } } } } /// A transformation from a modulator's value to a parameter value. #[derive(Debug, Clone, Copy, PartialEq)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Mapping { /// A range of values from a modulator. pub input_range: (f64, f64), /// The corresponding range of values of the parameter. pub output_range: (T, T), /// The curve to apply to the output. pub easing: Easing, } impl Mapping { /// Converts a `Mapping` to a `Mapping`. #[must_use = "This method returns a new Mapping and does not mutate the original."] pub fn to_>(self) -> Mapping { Mapping { input_range: self.input_range, output_range: (self.output_range.0.into(), self.output_range.1.into()), easing: self.easing, } } /// Transforms an input value to an output value using this mapping. #[must_use] pub fn map(self, input: f64) -> T where T: Tweenable, { let mut amount = (input - self.input_range.0) / (self.input_range.1 - self.input_range.0); amount = amount.clamp(0.0, 1.0); amount = self.easing.apply(amount); T::interpolate(self.output_range.0, self.output_range.1, amount) } /// Adds `rhs` to the minimum and maximum values of the output range. pub fn add_output(self, rhs: Rhs) -> Self where T: Add, Rhs: Copy, { Self { output_range: (self.output_range.0 + rhs, self.output_range.1 + rhs), ..self } } /// Subtracts `rhs` from the minimum and maximum values of the output range. pub fn sub_output(self, rhs: Rhs) -> Self where T: Sub, Rhs: Copy, { Self { output_range: (self.output_range.0 - rhs, self.output_range.1 - rhs), ..self } } /// Multiplies the minimum and maximum values of the output range by `rhs`. pub fn mul_output(self, rhs: Rhs) -> Self where T: Mul, Rhs: Copy, { Self { output_range: (self.output_range.0 * rhs, self.output_range.1 * rhs), ..self } } /// Divides the minimum and maximum values of the output range by `rhs`. pub fn div_output(self, rhs: Rhs) -> Self where T: Div, Rhs: Copy, { Self { output_range: (self.output_range.0 / rhs, self.output_range.1 / rhs), ..self } } /// Sets the minimum and maximum values of the output range to `x % rhs`. pub fn rem_output(self, rhs: Rhs) -> Self where T: Rem, Rhs: Copy, { Self { output_range: (self.output_range.0 % rhs, self.output_range.1 % rhs), ..self } } /// Negates the minimum and maximum values of the output range. pub fn neg_output(self) -> Self where T: Neg, { Self { output_range: (-self.output_range.0, -self.output_range.1), ..self } } }