Skip to content

Commit acfedb9

Browse files
committed
sound effects work; music is a little worse :(
1 parent 52fbb5f commit acfedb9

5 files changed

Lines changed: 171 additions & 120 deletions

File tree

src/domain/apu.rs

Lines changed: 35 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,8 @@ use std::collections::VecDeque;
22

33
const CPU_HZ: f64 = 4_194_304.0;
44
const FRAME_CYCLES: u32 = 70_224;
5-
pub(crate) const OUTPUT_SAMPLE_RATE_HZ: f64 = 48_000.0;
6-
const CYCLES_PER_SAMPLE: f64 = CPU_HZ / OUTPUT_SAMPLE_RATE_HZ;
7-
const MAX_SAMPLE_QUEUE: usize = 8_192;
5+
pub(crate) const DEFAULT_OUTPUT_SAMPLE_RATE_HZ: f64 = 48_000.0;
6+
const MAX_SAMPLE_QUEUE: usize = 2_048;
87

98
const REG_NR10: u16 = 0xFF10;
109
const REG_NR11: u16 = 0xFF11;
@@ -35,7 +34,6 @@ const REG_NR51: u16 = 0xFF25;
3534
const REG_NR52: u16 = 0xFF26;
3635

3736
const FREQ_DIVISOR: u32 = 131072;
38-
const NOISE_CLOCK_BASE: u32 = 524288;
3937
const FRAME_SEQUENCER_CYCLES: u32 = 8192;
4038

4139
const DUTY_CYCLES: [[u8; 8]; 4] = [
@@ -611,7 +609,7 @@ impl NoiseChannel {
611609

612610
let divisor = Self::divisor_value(self.divisor_code);
613611
let shift = self.shift_clock_frequency;
614-
let threshold = (NOISE_CLOCK_BASE / (divisor << shift)) / 2;
612+
let threshold = divisor << (shift + 4);
615613

616614
self.timer = self.timer.wrapping_add(cycles);
617615

@@ -732,6 +730,8 @@ pub struct Apu {
732730
wave_channel: WaveChannel,
733731
noise_channel: NoiseChannel,
734732
sample_cycle_accumulator: f64,
733+
sample_rate_hz: f64,
734+
cycles_per_sample: f64,
735735
samples: VecDeque<[i32; 2]>,
736736
current_sample: i32,
737737
current_sample_left: i32,
@@ -752,6 +752,8 @@ impl Apu {
752752
wave_channel: WaveChannel::new(),
753753
noise_channel: NoiseChannel::new(),
754754
sample_cycle_accumulator: 0.0,
755+
sample_rate_hz: DEFAULT_OUTPUT_SAMPLE_RATE_HZ,
756+
cycles_per_sample: CPU_HZ / DEFAULT_OUTPUT_SAMPLE_RATE_HZ,
755757
samples: VecDeque::new(),
756758
current_sample: 0,
757759
current_sample_left: 0,
@@ -776,8 +778,8 @@ impl Apu {
776778
self.noise_channel.step(cycles);
777779

778780
self.sample_cycle_accumulator += cycles as f64;
779-
while self.sample_cycle_accumulator >= CYCLES_PER_SAMPLE {
780-
self.sample_cycle_accumulator -= CYCLES_PER_SAMPLE;
781+
while self.sample_cycle_accumulator >= self.cycles_per_sample {
782+
self.sample_cycle_accumulator -= self.cycles_per_sample;
781783
self.mix_sample();
782784
if self.samples.len() >= MAX_SAMPLE_QUEUE {
783785
self.samples.pop_front();
@@ -797,41 +799,14 @@ impl Apu {
797799
self.wave_channel.tick_length();
798800
self.noise_channel.tick_length();
799801
}
800-
1 => {
801-
self.pulse_channel.tick_sweep();
802-
self.pulse_channel.tick_length();
803-
self.pulse_channel2.tick_length();
804-
self.wave_channel.tick_length();
805-
self.noise_channel.tick_length();
806-
}
807-
2 => {
808-
self.pulse_channel.tick_length();
809-
self.pulse_channel2.tick_length();
810-
self.wave_channel.tick_length();
811-
self.noise_channel.tick_length();
812-
}
813-
3 => {
814-
self.pulse_channel.tick_envelope();
815-
self.pulse_channel2.tick_envelope();
816-
self.pulse_channel.tick_length();
817-
self.pulse_channel2.tick_length();
818-
self.wave_channel.tick_length();
819-
self.noise_channel.tick_length();
820-
}
821-
4 => {
802+
2 | 6 => {
822803
self.pulse_channel.tick_length();
823804
self.pulse_channel2.tick_length();
824805
self.wave_channel.tick_length();
825806
self.noise_channel.tick_length();
826-
}
827-
5 => {
828807
self.pulse_channel.tick_sweep();
829-
self.pulse_channel.tick_length();
830-
self.pulse_channel2.tick_length();
831-
self.wave_channel.tick_length();
832-
self.noise_channel.tick_length();
833808
}
834-
6 => {
809+
4 => {
835810
self.pulse_channel.tick_length();
836811
self.pulse_channel2.tick_length();
837812
self.wave_channel.tick_length();
@@ -840,10 +815,7 @@ impl Apu {
840815
7 => {
841816
self.pulse_channel.tick_envelope();
842817
self.pulse_channel2.tick_envelope();
843-
self.pulse_channel.tick_length();
844-
self.pulse_channel2.tick_length();
845-
self.wave_channel.tick_length();
846-
self.noise_channel.tick_length();
818+
self.noise_channel.tick_envelope();
847819
}
848820
_ => {}
849821
}
@@ -903,7 +875,7 @@ impl Apu {
903875

904876
pub fn samples_per_frame(&self) -> u32 {
905877
let frame_rate = CPU_HZ / FRAME_CYCLES as f64;
906-
(OUTPUT_SAMPLE_RATE_HZ / frame_rate).round() as u32
878+
(self.sample_rate_hz / frame_rate).round() as u32
907879
}
908880

909881
fn reset_state(&mut self) {
@@ -1095,7 +1067,23 @@ impl Apu {
10951067
}
10961068

10971069
pub fn sample_rate_hz(&self) -> f64 {
1098-
OUTPUT_SAMPLE_RATE_HZ
1070+
self.sample_rate_hz
1071+
}
1072+
1073+
pub fn set_sample_rate_hz(&mut self, sample_rate_hz: f64) {
1074+
if !sample_rate_hz.is_finite() || sample_rate_hz <= 0.0 {
1075+
return;
1076+
}
1077+
if (self.sample_rate_hz - sample_rate_hz).abs() < f64::EPSILON {
1078+
return;
1079+
}
1080+
self.sample_rate_hz = sample_rate_hz;
1081+
self.cycles_per_sample = CPU_HZ / sample_rate_hz;
1082+
self.sample_cycle_accumulator = 0.0;
1083+
self.samples.clear();
1084+
self.current_sample = 0;
1085+
self.current_sample_left = 0;
1086+
self.current_sample_right = 0;
10991087
}
11001088

11011089
pub fn has_sample(&self) -> bool {
@@ -1126,8 +1114,8 @@ impl Apu {
11261114
#[cfg(test)]
11271115
mod tests {
11281116
use super::{
1129-
Apu, CPU_HZ, CYCLES_PER_SAMPLE, FRAME_CYCLES, NoiseChannel, OUTPUT_SAMPLE_RATE_HZ,
1130-
PulseChannel, WaveChannel,
1117+
Apu, CPU_HZ, DEFAULT_OUTPUT_SAMPLE_RATE_HZ, FRAME_CYCLES, NoiseChannel, PulseChannel,
1118+
WaveChannel,
11311119
};
11321120

11331121
#[test]
@@ -1569,7 +1557,7 @@ mod tests {
15691557
let apu = Apu::new();
15701558
let rate = apu.sample_rate_hz();
15711559
assert!(
1572-
(rate - OUTPUT_SAMPLE_RATE_HZ).abs() < 0.1,
1560+
(rate - DEFAULT_OUTPUT_SAMPLE_RATE_HZ).abs() < 0.1,
15731561
"Sample rate should be ~48kHz, got {}",
15741562
rate
15751563
);
@@ -1580,7 +1568,7 @@ mod tests {
15801568
let mut apu = Apu::new();
15811569
assert!(!apu.has_sample());
15821570
assert_eq!(apu.sample(), 0);
1583-
let cycles_per_sample = CYCLES_PER_SAMPLE.ceil() as u32;
1571+
let cycles_per_sample = (CPU_HZ / apu.sample_rate_hz()).ceil() as u32;
15841572
let _ = apu.step(cycles_per_sample);
15851573
assert!(apu.has_sample());
15861574
let sample = apu.take_sample();
@@ -1591,7 +1579,7 @@ mod tests {
15911579
#[test]
15921580
fn apu_sample_is_clamped() {
15931581
let mut apu = Apu::new();
1594-
let cycles_per_sample = CYCLES_PER_SAMPLE.ceil() as u32;
1582+
let cycles_per_sample = (CPU_HZ / apu.sample_rate_hz()).ceil() as u32;
15951583
for _ in 0..10 {
15961584
let _ = apu.step(cycles_per_sample);
15971585
if apu.has_sample() {

src/domain/bus.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,10 @@ impl Bus {
353353
self.apu.sample_rate_hz()
354354
}
355355

356+
pub fn apu_set_sample_rate_hz(&mut self, sample_rate_hz: f64) {
357+
self.apu.set_sample_rate_hz(sample_rate_hz);
358+
}
359+
356360
pub fn apu_has_sample(&self) -> bool {
357361
self.apu.has_sample()
358362
}

src/domain/emulator.rs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use super::apu::OUTPUT_SAMPLE_RATE_HZ;
1+
use super::apu::DEFAULT_OUTPUT_SAMPLE_RATE_HZ;
22
use super::{Bus, Cartridge, Cpu, CpuError, Framebuffer, MbcError, Ppu};
33

44
#[derive(Debug)]
@@ -136,7 +136,13 @@ impl Emulator {
136136
self.bus
137137
.as_ref()
138138
.map(|bus| bus.apu_sample_rate_hz())
139-
.unwrap_or(OUTPUT_SAMPLE_RATE_HZ)
139+
.unwrap_or(DEFAULT_OUTPUT_SAMPLE_RATE_HZ)
140+
}
141+
142+
pub fn apu_set_sample_rate_hz(&mut self, sample_rate_hz: f64) {
143+
if let Some(bus) = self.bus.as_mut() {
144+
bus.apu_set_sample_rate_hz(sample_rate_hz);
145+
}
140146
}
141147

142148
pub fn apu_has_sample(&self) -> bool {
@@ -221,7 +227,7 @@ impl Emulator {
221227

222228
#[cfg(test)]
223229
mod tests {
224-
use super::Emulator;
230+
use super::{Emulator, DEFAULT_OUTPUT_SAMPLE_RATE_HZ};
225231
use crate::domain::cartridge::ROM_BANK_SIZE;
226232
use crate::domain::{Cartridge, FRAME_SIZE};
227233

@@ -253,7 +259,7 @@ mod tests {
253259
let emulator = emulator_with_rom();
254260
let rate = emulator.apu_sample_rate_hz();
255261
assert!(
256-
(rate - 48_000.0).abs() < 0.1,
262+
(rate - DEFAULT_OUTPUT_SAMPLE_RATE_HZ).abs() < 0.1,
257263
"Expected ~48kHz, got {}",
258264
rate
259265
);
@@ -309,7 +315,7 @@ mod tests {
309315
emulator.apu_reset();
310316
let rate = emulator.apu_sample_rate_hz();
311317
assert!(
312-
(rate - 48_000.0).abs() < 0.1,
318+
(rate - DEFAULT_OUTPUT_SAMPLE_RATE_HZ).abs() < 0.1,
313319
"Expected ~48kHz, got {}",
314320
rate
315321
);

0 commit comments

Comments
 (0)