use super::PtvError;
use crate::data::{FromRead, FromReadVar, WriteTo, WriteVarTo};
use std::io::{Read, Seek, Write};
#[derive(Clone, Debug, PartialEq)]
pub struct PtvEnvelope {
pub points: Box<[(i32, i32)]>,
pub release: i32,
pub ticks_per_second: i32,
}
impl PtvEnvelope {
pub fn new(points: Box<[(i32, i32)]>, release: i32) -> Self {
Self {
points,
release,
ticks_per_second: 1000,
}
}
}
impl FromRead<Self> for PtvEnvelope {
type Error = PtvError;
fn from_read<R: Read>(source: &mut R) -> Result<Self, Self::Error> {
let ticks_per_second = i32::from_read_var(source)?;
let point_count: usize = i32::from_read_var(source)?
.try_into()
.map_err(|_| PtvError::Invalid)?;
if (i32::from_read_var(source)? != 0) || (i32::from_read_var(source)? != 1) {
return Err(PtvError::Invalid);
}
let mut points = vec![];
let mut prev_x = 0;
for _ in 0..point_count {
let (dx, y) = <(i32, i32)>::from_read_var(source)?;
prev_x += dx;
points.push((prev_x, y));
}
let points = points.into_boxed_slice();
let (release, _release_y) = <(i32, i32)>::from_read_var(source)?;
Ok(Self {
points,
release,
ticks_per_second,
})
}
}
impl WriteTo for PtvEnvelope {
type Error = PtvError;
fn write_to<W: Write + Seek>(&self, sink: &mut W) -> Result<u64, Self::Error> {
let start_pos = self.ticks_per_second.write_var_to(sink)?;
i32::try_from(self.points.len())
.map_err(|_| PtvError::Oversized)?
.write_var_to(sink)?;
0_i32.write_var_to(sink)?;
1_i32.write_var_to(sink)?;
let mut prev_x = 0;
for &(x, y) in self.points.iter() {
(x - prev_x, y).write_var_to(sink)?;
prev_x = x;
}
(self.release, 0_i32).write_var_to(sink)?;
Ok(start_pos)
}
}
impl Default for PtvEnvelope {
fn default() -> Self {
Self::new(Box::new([(0, 96)]), 1)
}
}