soundchip/prelude/values/
normal_signed.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
use crate::prelude::KnotValue;
use core::fmt::{Display, Formatter};

/// Stored internally as i16, allows converting to/from a -1.0 to 1.0 f32 range.
/// Any f32 value outside of this range will be clipped.
#[derive(Clone, Copy, Default)]
pub struct NormalSigned(i16);

const MAX: f32 = i16::MAX as f32;

/// Returns an f32 value between -1.0 and 1.0 (inclusive).
impl Into<f32> for NormalSigned {
    fn into(self) -> f32 {
        self.0 as f32 / MAX
    }
}

/// Will clamp values outside valid range of -1.0 to 1.0.
impl From<f32> for NormalSigned {
    fn from(value: f32) -> Self {
        let clamped = (value.clamp(-1.0, 1.0) * MAX) as i16;
        Self(clamped)
    }
}

impl Display for NormalSigned {
    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
        let n = self.0 as f32 / MAX;
        f.write_fmt(format_args!("{}", n))
    }
}

impl core::fmt::Debug for NormalSigned {
    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
        let n = self.0 as f32 / MAX;
        f.write_fmt(format_args!("NormalSigned({})", n))
    }
}

impl PartialEq for NormalSigned {
    fn eq(&self, other: &Self) -> bool {
        self.0 == other.0
    }
}

impl KnotValue for NormalSigned {}


#[test]
fn normal_signed_value_clip() {
    let a = -1.5;
    let a_normal = NormalSigned::from(a);
    let a_converted: f32 = a_normal.into();
    assert_eq!(a_converted, -1.0); // clipped to -1.0

    let a = 1.5;
    let a_normal = NormalSigned::from(a);
    let a_converted: f32 = a_normal.into();
    assert_eq!(a_converted, 1.0); // clipped to 1.0
}

#[test]
// NOT lossless, tiny changes can occur. Less precise than Normal,
// four decimals versus five.
fn normal_signed_value_precision() {
    for n in 0 .. 10 {
        let a = n as f32 / 10.0;
        let a_normal = NormalSigned::from(a);
        let a_converted: f32 = a_normal.into();
        assert!((a_converted - a).abs() < 0.0001);
    }
}