use crate::{
result::{ProjectReadError, ReadResult},
timing::{Meas, Tick, Timing, meas_to_tick, tick_to_meas},
};
pub struct Master {
pub timing: Timing,
pub loop_points: LoopPoints,
pub(crate) meas_num: Meas,
}
#[derive(Default)]
pub struct LoopPoints {
pub last: Meas,
pub repeat: Meas,
}
impl Default for Master {
fn default() -> Self {
Self {
timing: Timing::default(),
loop_points: LoopPoints::default(),
meas_num: 1,
}
}
}
impl Master {
pub(crate) fn get_last_tick(&self) -> Tick {
meas_to_tick(self.loop_points.last, self.timing)
}
pub(crate) const fn get_play_meas(&self) -> Meas {
if self.loop_points.last != 0 {
self.loop_points.last
} else {
self.meas_num
}
}
pub(crate) fn adjust_meas_num(&mut self, tick: Tick) {
self.meas_num = std::cmp::max(self.meas_num, tick_to_meas(tick, self.timing));
if self.loop_points.repeat >= self.meas_num {
self.loop_points.repeat = 0;
}
if self.loop_points.last > self.meas_num {
self.loop_points.last = self.meas_num;
}
}
pub(crate) fn read_v5(rd: &mut crate::io::Reader) -> ReadResult<Self> {
let size = rd.next::<u32>()?;
if size != 15 {
return Err(ProjectReadError::FmtUnknown);
}
let beat_clock = rd.next::<u16>()?;
let beat_num = rd.next::<u8>()?;
let beat_tempo = rd.next::<f32>()?;
let clock_repeat = rd.next::<u32>()?;
let clock_last = rd.next::<u32>()?;
let timing = Timing {
ticks_per_beat: beat_clock,
bpm: beat_tempo,
beats_per_meas: beat_num,
};
let loop_points = LoopPoints {
repeat: clock_repeat / u32::from(u16::from(beat_num) * beat_clock),
last: clock_last / u32::from(u16::from(beat_num) * beat_clock),
};
Ok(Self {
timing,
loop_points,
meas_num: 1,
})
}
pub(crate) fn write_v5(&self, out: &mut Vec<u8>) {
let size: u32 = 15;
out.extend_from_slice(&size.to_le_bytes());
out.extend_from_slice(&self.timing.ticks_per_beat.to_le_bytes());
out.extend_from_slice(&self.timing.beats_per_meas.to_le_bytes());
out.extend_from_slice(&self.timing.bpm.to_le_bytes());
let clock_repeat: u32 = meas_to_tick(self.loop_points.repeat, self.timing);
let clock_last: u32 = meas_to_tick(self.loop_points.last, self.timing);
out.extend_from_slice(&clock_repeat.to_le_bytes());
out.extend_from_slice(&clock_last.to_le_bytes());
}
}