Initial commit: NES emulator with GTK4 desktop frontend
Some checks failed
CI / rust (push) Has been cancelled
Some checks failed
CI / rust (push) Has been cancelled
Full NES emulation: CPU, PPU, APU, 47 mappers, iNES/NES 2.0 parsing. GTK4 desktop client with HeaderBar, pixel-perfect Cairo rendering, drag-and-drop ROM loading, and keyboard shortcuts. 187 tests covering core emulation, mappers, and runtime.
This commit is contained in:
39
src/runtime/audio.rs
Normal file
39
src/runtime/audio.rs
Normal file
@@ -0,0 +1,39 @@
|
||||
use crate::runtime::VideoMode;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct AudioMixer {
|
||||
sample_rate: u32,
|
||||
samples_per_cpu_cycle: f64,
|
||||
sample_accumulator: f64,
|
||||
}
|
||||
|
||||
impl AudioMixer {
|
||||
pub fn new(sample_rate: u32, mode: VideoMode) -> Self {
|
||||
let cpu_hz = mode.cpu_hz();
|
||||
Self {
|
||||
sample_rate,
|
||||
samples_per_cpu_cycle: sample_rate as f64 / cpu_hz,
|
||||
sample_accumulator: 0.0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sample_rate(&self) -> u32 {
|
||||
self.sample_rate
|
||||
}
|
||||
|
||||
pub fn reset(&mut self) {
|
||||
self.sample_accumulator = 0.0;
|
||||
}
|
||||
|
||||
pub fn push_cycles(&mut self, cpu_cycles: u8, apu_regs: &[u8; 0x20], out: &mut Vec<f32>) {
|
||||
self.sample_accumulator += self.samples_per_cpu_cycle * f64::from(cpu_cycles);
|
||||
let samples = self.sample_accumulator.floor() as usize;
|
||||
self.sample_accumulator -= samples as f64;
|
||||
|
||||
// Current core does not expose a final mixed PCM stream yet.
|
||||
// Use DMC output level as a stable interim signal in [-1.0, 1.0].
|
||||
let dmc = apu_regs[0x11] & 0x7F;
|
||||
let sample = (f32::from(dmc) / 63.5) - 1.0;
|
||||
out.extend(std::iter::repeat_n(sample, samples));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user