use std::sync::{Arc, RwLock}; use lewton::inside_ogg::OggStreamReader; use num_traits::clamp; use crate::framework::filesystem::File; use crate::sound::stuff::cubic_interp; use crate::sound::wav::WavFormat; pub(crate) struct OggPlaybackEngine { intro_music: Option>>>>, loop_music: Option>>>>, output_format: WavFormat, playing_intro: bool, position: u64, buffer: Vec, } pub struct SavedOggPlaybackState { intro_music: Option>>>>, loop_music: Option>>>>, playing_intro: bool, position: u64, } impl OggPlaybackEngine { pub fn new() -> OggPlaybackEngine { OggPlaybackEngine { intro_music: None, loop_music: None, output_format: WavFormat { channels: 2, sample_rate: 44100, bit_depth: 16, }, playing_intro: false, position: 0, buffer: Vec::with_capacity(4096), } } pub fn set_sample_rate(&mut self, sample_rate: usize) {} pub fn get_state(&self) -> SavedOggPlaybackState { SavedOggPlaybackState { intro_music: self.intro_music.clone(), loop_music: self.loop_music.clone(), playing_intro: self.playing_intro, position: self.position, } } pub fn set_state(&mut self, state: SavedOggPlaybackState) { self.intro_music = state.intro_music; self.loop_music = state.loop_music; self.playing_intro = state.playing_intro; self.position = state.position; } pub fn start_single(&mut self, loop_music: Box>) { self.intro_music = None; self.loop_music = Some(Arc::new(RwLock::new(loop_music))); self.playing_intro = false; self.position = 0; } pub fn start_multi( &mut self, intro_music: Box>, loop_music: Box>, ) { self.intro_music = Some(Arc::new(RwLock::new(intro_music))); self.loop_music = Some(Arc::new(RwLock::new(loop_music))); self.playing_intro = true; self.position = 0; } pub fn rewind(&mut self) { if let Some(music) = self.intro_music.as_ref() { let _ = music.write().unwrap().seek_absgp_pg(0); self.position = 0; self.playing_intro = true; } else { if let Some(music) = self.loop_music.as_ref() { let _ = music.write().unwrap().seek_absgp_pg(0); } self.position = 0; self.playing_intro = false; } } fn decode(&mut self) { if self.playing_intro { if let Some(music) = self.intro_music.as_ref() { let mut music = music.write().unwrap(); let mut buf = match music.read_dec_packet_itl() { Ok(Some(buf)) => buf, Ok(None) | Err(_) => { self.playing_intro = false; return; } }; self.position = music.get_last_absgp().unwrap_or(0); buf = self.resample_buffer( buf, music.ident_hdr.audio_sample_rate, music.ident_hdr.audio_channels, ); self.buffer.append(&mut buf); } else { self.playing_intro = false; } } else { if let Some(music) = self.loop_music.as_ref() { let mut music = music.write().unwrap(); let mut buf = match music.read_dec_packet_itl() { Ok(Some(buf)) => buf, Ok(None) => { if let Err(e) = music.seek_absgp_pg(0) { vec![0, 1000] } else { return; } } Err(e) => { vec![0, 1000] } }; self.position = music.get_last_absgp().unwrap_or(0); buf = self.resample_buffer( buf, music.ident_hdr.audio_sample_rate, music.ident_hdr.audio_channels, ); self.buffer.append(&mut buf); } else { let mut buf = vec![0; 1000]; self.buffer.append(&mut buf); } } } fn resample_buffer(&self, mut data: Vec, sample_rate: u32, channels: u8) -> Vec { if sample_rate != self.output_format.sample_rate { let mut tmp_data = Vec::new(); let mut pos = 0.0; let mut phase = sample_rate as f32 / self.output_format.sample_rate as f32; loop { if pos >= data.len() as f32 { data = tmp_data; break; } let s = unsafe { let upos = pos as usize; let s1 = (*data.get_unchecked(upos) as f32) / 32768.0; let s2 = (*data.get_unchecked(clamp(upos + 1, 0, data.len() - 1)) as f32) / 32768.0; let s3 = (*data.get_unchecked(clamp(upos + 2, 0, data.len() - 1)) as f32) / 32768.0; let s4 = (*data.get_unchecked(upos.saturating_sub(1)) as f32) / 32768.0; (cubic_interp(s1, s2, s4, s3, pos.fract()) * 32768.0) as i16 }; tmp_data.push(s); pos += phase; } } data } pub fn render_to(&mut self, buf: &mut [u16]) -> usize { while self.buffer.len() < buf.len() { self.decode(); } self.buffer .drain(0..buf.len()) .map(|n| n as u16 ^ 0x8000) .zip(buf.iter_mut()) .for_each(|(n, tgt)| *tgt = n); buf.len() } }