#[derive(Clone, Copy)]
pub struct OsciArgs {
pub volume: i16,
pub sample_num: u32,
}
#[derive(Copy, Clone, Default, Debug)]
pub struct OsciPt {
pub x: u16,
pub y: i16,
}
impl OsciPt {
pub const ZERO: Self = Self { x: 0, y: 0 };
}
#[must_use]
pub fn overtone(args: OsciArgs, points: &[OsciPt], index: u16) -> f64 {
let overtone: f64 = points
.iter()
.map(|pt| {
let phase = 2.0
* std::f64::consts::PI
* (f64::from(pt.x) * f64::from(index) / f64::from(args.sample_num));
phase.sin() * f64::from(pt.y) / f64::from(pt.x) / 128.
})
.sum();
overtone * f64::from(args.volume) / 128.
}
#[must_use]
pub fn coord(args: OsciArgs, points: &[OsciPt], index: u16, hres: u16) -> f64 {
let len = points.len();
if len == 0 {
return 0.0;
}
let mut i: u16 = (u32::from(hres) * u32::from(index) / args.sample_num).try_into().unwrap();
let mut c = 0;
while c < len {
if points[c].x > i {
break;
}
c += 1;
}
let (x1, y1, x2, y2) = if c == len {
(points[c - 1].x, points[c - 1].y, hres, points[0].y)
} else if c != 0 {
(points[c - 1].x, points[c - 1].y, points[c].x, points[c].y)
} else {
(points[0].x, points[0].y, points[0].x, points[0].y)
};
let w: u16 = x2 - x1;
i = i.saturating_sub(x1);
let h: i16 = y2 - y1;
let work = if i != 0 {
f64::from(y1) + f64::from(h) * f64::from(i) / f64::from(w)
} else {
f64::from(y1)
};
work * f64::from(args.volume) / 128. / 128.
}