use crate::interface::DacInterface; pub enum Direction { Up, Down, } pub struct DpcmSample { direction: Direction, // only 3 bits step_count: u8, } impl DpcmSample { pub fn new(byte: u8, sub_index: usize) -> Self { let data = if sub_index == 0 { byte & 0x0F } else { byte >> 4 }; let direction = match data & 0x1 { 0x1 => Direction::Up, 0x0 => Direction::Down, _ => Direction::Up, }; let step_count = data >> 1; Self { direction, step_count, } } } pub struct Dac<'a, T: DacInterface> { output: T, data: Option<&'a [u8]>, index: usize, } impl<'a, T: DacInterface> Dac<'a, T> { pub fn new(output: T) -> Self { Self { output, data: None, index: 0, } } pub fn load_data(&mut self, data: &'a [u8]) { self.data = Some(data); } pub fn seek_to_sample(&mut self, index: usize) { self.index = index; } pub fn output_next(&mut self) { if let Some(data) = self.data { self.index = self.index + 1; // reset the index to 0 if we roll over if (self.index >= data.len()) { self.index = 0; } self.output.write_amplitude(data[self.index]); // self.output.write_amplitude(100); } } } pub struct DpcmDac<'a, T: DacInterface> { output: T, data: Option<&'a [u8]>, index: usize, prev_amplitude: usize, step_size: usize, min: usize, max: usize, } impl<'a, T: DacInterface> DpcmDac<'a, T> { pub fn new(output: T) -> Self { Self { output, data: None, index: 0, prev_amplitude: 0x80, step_size: 0x3, min: 0x19, max: 0xe6, } } pub fn load_data(&mut self, data: &'a [u8]) { self.data = Some(data); } pub fn seek_to_sample(&mut self, index: usize) { self.index = index; } // output the next sampe. returns true if there are samples remaining, false if there are no samples remaining. pub fn output_next(&mut self) -> bool { if let Some(data) = self.data { let sub_index = 1 - self.index % 2; let sample = DpcmSample::new(data[self.index / 2], sub_index); let new_amplitude = match sample.direction { Direction::Down => self.prev_amplitude.saturating_sub(sample.step_count as usize * self.step_size).max(self.min), Direction ::Up => (self.prev_amplitude + (sample.step_count as usize * self.step_size)).min(self.max), }; // calculate normalized amplitude and write out let normalized_amplitude = (new_amplitude - self.min) * 100 / (self.max - self.min); self.output.write_amplitude(normalized_amplitude as u8); self.prev_amplitude = new_amplitude; // increment the sample index let mut samples_remaining = true; self.index = self.index + 1; // reset the index to 0 if we roll over if (self.index >= data.len() * 2) { self.index = 0; self.prev_amplitude = 0x74; samples_remaining = false; } // return whether or not we have samples remaining samples_remaining } else { // if the sample failed to load, we (duh) have no more samples remaining false } } }