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) { self.output_format.sample_rate = sample_rate as u32; } 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 { let _ = music.write().unwrap().seek_absgp_pg(0); self.position = 0; self.playing_intro = true; } else { if let Some(music) = &self.loop_music { 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 { let mut music = music.write().unwrap(); let mut buf = match music.read_dec_packet_itl() { Ok(Some(buf)) => buf, Ok(None) => { self.playing_intro = false; return; } Err(e) => { log::error!("Error decoding intro: {}", e); 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 { let mut music = music.write().unwrap(); let mut buf = match music.read_dec_packet_itl() { Ok(Some(buf)) => buf, Ok(None) => { if music.seek_absgp_pg(0).is_ok() { return; } vec![0, 1000] } Err(_) => { 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 data.is_empty() { return data; } if sample_rate != self.output_format.sample_rate { let mut tmp_data = Vec::with_capacity( (data.len() as f64 * self.output_format.sample_rate as f64 / sample_rate as f64) as usize, ); let mut pos = 0.0; let phase = sample_rate as f32 / self.output_format.sample_rate as f32; let num_samples = data.len() / channels as usize; if channels == 1 { loop { if pos >= num_samples 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(clamp(upos.saturating_sub(1), 0, data.len() - 1)) as f32) / 32768.0; (cubic_interp(s1, s2, s4, s3, pos.fract()) * 32768.0) as i16 }; tmp_data.push(s); pos += phase; } } else if channels == 2 { let max_samp = (num_samples - 1) * 2; // unrolled for performance reasons loop { if pos >= num_samples as f32 { data = tmp_data; break; } let sl = unsafe { let upos = pos as usize; let max = max_samp as usize; let s1 = (*data.get_unchecked(upos * 2) as f32) / 32768.0; let s2 = (*data.get_unchecked(clamp((upos + 1) * 2, 0, max)) as f32) / 32768.0; let s3 = (*data.get_unchecked(clamp((upos + 2) * 2, 0, max)) as f32) / 32768.0; let s4 = (*data.get_unchecked(clamp(upos.saturating_sub(1) * 2, 0, max)) as f32) / 32768.0; (cubic_interp(s1, s2, s4, s3, pos.fract()) * 32768.0) as i16 }; tmp_data.push(sl); let sr = unsafe { let upos = pos as usize; let max = max_samp as usize + 1; let s1 = (*data.get_unchecked(upos * 2 + 1) as f32) / 32768.0; let s2 = (*data.get_unchecked(clamp((upos + 1) * 2 + 1, 1, max)) as f32) / 32768.0; let s3 = (*data.get_unchecked(clamp((upos + 2) * 2 + 1, 1, max)) as f32) / 32768.0; let s4 = (*data.get_unchecked(clamp(upos.saturating_sub(1) * 2 + 1, 0, max)) as f32) / 32768.0; (cubic_interp(s1, s2, s4, s3, pos.fract()) * 32768.0) as i16 }; tmp_data.push(sr); pos += phase; } } else { let cc = channels as usize; let max_samp = (num_samples - 1) * cc; loop { if pos >= num_samples as f32 { data = tmp_data; break; } for c in 0..channels { let s = unsafe { let upos = pos as usize; let max = max_samp + c as usize; let s1 = (*data.get_unchecked(upos * cc + c as usize) as f32) / 32768.0; let s2 = (*data.get_unchecked(clamp((upos + 1) * cc + c as usize, c as usize, max)) as f32) / 32768.0; let s3 = (*data.get_unchecked(clamp((upos + 2) * cc + c as usize, c as usize, max)) as f32) / 32768.0; let s4 = (*data.get_unchecked(clamp(upos.saturating_sub(1) * cc + c as usize, c as usize, max)) as f32) / 32768.0; (cubic_interp(s1, s2, s4, s3, pos.fract()) * 32768.0) as i16 }; tmp_data.push(s); } pos += phase; } } } if channels == 1 { let mut tmp_data = Vec::with_capacity(data.len() * 2); for s in data.iter().copied() { tmp_data.push(s); tmp_data.push(s); } data = tmp_data; } 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() } }