Master System / Game Gear audio resampling code
9pub const NTSC_MCLK_FREQUENCY: f64 = 53_693_175.0; 10pub const PAL_MCLK_FREQUENCY: f64 = 53_203_424.0; 11 12pub(crate) trait TimingModeExt { 13 fn mclk_frequency(self) -> f64; 14} 15 16impl TimingModeExt for TimingMode { 17 fn mclk_frequency(self) -> f64 { 18 match self { 19 Self::Ntsc => NTSC_MCLK_FREQUENCY, 20 Self::Pal => PAL_MCLK_FREQUENCY, 21 } 22 } 23} 24 25fn compute_psg_frequency(console_mclk_frequency: f64) -> f64 { 26 console_mclk_frequency / 15.0 / 16.0 27} 28 29#[must_use] 30pub fn new_psg_dc_offset(timing_mode: TimingMode) -> FirstOrderIirFilter { 31 dsp::design::butterworth( 32 5.0, 33 compute_psg_frequency(timing_mode.mclk_frequency()), 34 FilterType::HighPass, 35 ) 36} 37 38#[derive(Debug, Clone, Encode, Decode)] 39pub(crate) struct AudioResampler { 40 dc_offset_l: FirstOrderIirFilter, 41 dc_offset_r: FirstOrderIirFilter, 42 psg_resampler: PerformanceSincResampler<2>, 43} 44 45impl AudioResampler { 46 pub fn new(timing_mode: TimingMode) -> Self { 47 Self { 48 dc_offset_l: new_psg_dc_offset(timing_mode), 49 dc_offset_r: new_psg_dc_offset(timing_mode), 50 psg_resampler: PerformanceSincResampler::new( 51 compute_psg_frequency(timing_mode.mclk_frequency()), 52 48000.0, 53 ), 54 } 55 } 56 57 pub fn update_timing_mode(&mut self, timing_mode: TimingMode) { 58 let psg_frequency = compute_psg_frequency(timing_mode.mclk_frequency()); 59 self.psg_resampler.update_source_frequency(psg_frequency); 60 } 61 62 pub fn collect_sample(&mut self, sample_l: f64, sample_r: f64) { 63 let sample_l = self.dc_offset_l.filter(sample_l); 64 let sample_r = self.dc_offset_r.filter(sample_r); 65 self.psg_resampler.collect([sample_l, sample_r]); 66 } 67 68 pub fn output_samples<A: AudioOutput>(&mut self, audio_output: &mut A) -> Result<(), A::Err> { 69 while let Some([sample_l, sample_r]) = self.psg_resampler.output_buffer_pop_front() { 70 audio_output.push_sample(sample_l, sample_r)?; 71 } 72 73 Ok(()) 74 } 75 76 pub fn update_output_frequency(&mut self, output_frequency: u64) { 77 self.psg_resampler.update_output_frequency(output_frequency as f64); 78 } 79}