apu.rsannotatedapu.rssource381 lines · 13.4 KB · raw

Game Boy APU (audio processing unit)

3pub mod components;
4pub mod noise;
5pub mod pulse;
6mod wavetable;
8use crate::HardwareMode;
9use crate::api::GameBoyEmulatorConfig;
10use crate::apu::noise::NoiseChannel;
11use crate::apu::pulse::PulseChannel;
12use crate::apu::wavetable::WavetableChannel;
13use crate::audio::{GB_APU_FREQUENCY, GameBoyResampler};
14use crate::cgb::CpuSpeed;
15use crate::timer::GbTimer;
16use bincode::{Decode, Encode};
17use jgenesis_common::frontend::AudioOutput;
18use jgenesis_common::num::GetBit;
19use std::array;
20
21#[derive(Debug, Clone, Copy, Encode, Decode)]
22pub struct StereoControl {
23    pub left_volume: u8,
24    pub right_volume: u8,
25    pub left_channels: [bool; 4],
26    pub right_channels: [bool; 4],
27    // Vin functionality is not emulated but some test ROMs depend on these bits being R/W
28    vin_bits: u8,
29}
30
31impl Default for StereoControl {
32    fn default() -> Self {
33        Self::new()
34    }
35}
36
37impl StereoControl {
38    #[must_use]
39    pub fn new() -> Self {
40        // Initial state from https://gbdev.io/pandocs/Power_Up_Sequence.html#hardware-registers
41        Self {
42            left_volume: 7,
43            right_volume: 7,
44            vin_bits: 0,
45            left_channels: [true; 4],
46            right_channels: [true, true, false, false],
47        }
48    }
49
50    #[must_use]
51    pub fn zero() -> Self {
52        Self {
53            left_volume: 0,
54            right_volume: 0,
55            vin_bits: 0,
56            left_channels: [false; 4],
57            right_channels: [false; 4],
58        }
59    }
60
61    #[must_use]
62    pub fn read_volume(&self) -> u8 {
63        (self.left_volume << 4) | self.right_volume | self.vin_bits
64    }
65
66    pub fn write_volume(&mut self, value: u8) {
67        // NR50: Stereo volume controls
68        self.left_volume = (value >> 4) & 0x07;
69        self.right_volume = value & 0x07;
70        self.vin_bits = value & 0x88;
71
72        log::trace!("NR50 write");
73        log::trace!("  L volume: {}", self.left_volume);
74        log::trace!("  R volume: {}", self.right_volume);
75    }
76
77    #[must_use]
78    pub fn read_enabled(&self) -> u8 {
79        let high_nibble = stereo_channels_to_nibble(self.left_channels);
80        let low_nibble = stereo_channels_to_nibble(self.right_channels);
81        (high_nibble << 4) | low_nibble
82    }
83
84    pub fn write_enabled(&mut self, value: u8) {
85        // NR51: Stereo panning controls
86        self.left_channels = array::from_fn(|i| value.bit(4 + i as u8));
87        self.right_channels = array::from_fn(|i| value.bit(i as u8));
88
89        log::trace!("NR51 write");
90        log::trace!("  L enabled: {:?}", self.left_channels);
91        log::trace!("  R enabled: {:?}", self.right_channels);
92    }
93}
94
95fn stereo_channels_to_nibble(channels: [bool; 4]) -> u8 {
96    channels.into_iter().enumerate().map(|(i, b)| u8::from(b) << i).reduce(|a, b| a | b).unwrap()
97}
98
99#[derive(Debug, Clone, Encode, Decode)]
100struct Dac {
101    analog_sample: f64,
102    output_level: f64,
103}
104
105impl Dac {
106    fn new() -> Self {
107        Self { analog_sample: 0.0, output_level: 0.0 }
108    }
109
110    fn digital_to_analog(&mut self, sample: Option<u8>) -> f64 {
111        // When the DAC is enabled or disabled, gradually fade in/out over a very short period.
112        // Some games depend on this to avoid buzzing due to how they use the wavetable channel, e.g. Cannon Fodder
113        // 1/20000th of a second period is based on what SameBoy does; I think in actual hardware this can vary
114        // because it's an emergent property of the hardware, not an intentional audio effect
115        const FADE_DELTA: f64 = 20000.0 / GB_APU_FREQUENCY;
116
117        match sample {
118            Some(sample) => {
119                // Convert from digital [0, 15] to analog [-1, +1] but inverted
120                //   Digital 0  -> Analog +1
121                //   Digital 15 -> Analog -1
122                self.analog_sample = (f64::from(15 - sample) - 7.5) / 7.5;
123
124                // Gradually fade in if DAC was just enabled
125                self.output_level = (self.output_level + FADE_DELTA).clamp(0.0, 1.0);
126            }
127            None => {
128                // DAC is disabled; gradually fade out, keep current analog sample output
129                self.output_level = (self.output_level - FADE_DELTA).clamp(0.0, 1.0);
130            }
131        }
132
133        self.analog_sample * self.output_level
134    }
135}
136
137#[derive(Debug, Clone, Encode, Decode)]
138pub(crate) struct Apu {
139    hardware_mode: HardwareMode,
140    enabled: bool,
141    pulse_1: PulseChannel,
142    pulse_2: PulseChannel,
143    wavetable: WavetableChannel,
144    noise: NoiseChannel,
145    stereo_control: StereoControl,
146    dacs: [Dac; 4],
147    frame_sequencer_step: u8,
148    previous_div_bit: bool,
149    resampler: GameBoyResampler,
150}
151
152impl Apu {
153    pub fn new(config: GameBoyEmulatorConfig, hardware_mode: HardwareMode) -> Self {
154        Self {
155            hardware_mode,
156            enabled: true,
157            pulse_1: PulseChannel::new(),
158            pulse_2: PulseChannel::new(),
159            wavetable: WavetableChannel::new(hardware_mode),
160            noise: NoiseChannel::new(),
161            stereo_control: StereoControl::new(),
162            dacs: array::from_fn(|_| Dac::new()),
163            frame_sequencer_step: 0,
164            previous_div_bit: false,
165            resampler: GameBoyResampler::new(&config),
166        }
167    }
168
169    pub fn tick_m_cycle(&mut self, timer: &GbTimer, cpu_speed: CpuSpeed) {
170        // In CGB double speed mode, the DIV-APU counter reads DIV bit 5 instead of 4 so that it
171        // continues to tick at 512 Hz instead of running twice as fast
172        let div_bit_index = match cpu_speed {
173            CpuSpeed::Normal => 4,
174            CpuSpeed::Double => 5,
175        };
176
177        let div_bit = timer.read_div().bit(div_bit_index);
178        if self.previous_div_bit && !div_bit {
179            // Clock frame sequencer
180            self.frame_sequencer_step = (self.frame_sequencer_step + 1) & 7;
181
182            if self.enabled {
183                if !self.frame_sequencer_step.bit(0) {
184                    self.clock_length_counters();
185                }
186
187                if self.frame_sequencer_step == 7 {
188                    self.clock_envelopes();
189                }
190
191                if self.frame_sequencer_step == 2 || self.frame_sequencer_step == 6 {
192                    self.pulse_1.clock_sweep();
193                }
194            }
195        }
196        self.previous_div_bit = div_bit;
197
198        if !self.enabled {
199            // If APU is disabled, output constant 0s
200            self.resampler.collect_sample(0.0, 0.0);
201            return;
202        }
203
204        self.pulse_1.tick_m_cycle();
205        self.pulse_2.tick_m_cycle();
206        self.noise.tick_m_cycle();
207
208        for _ in 0..2 {
209            self.wavetable.tick_2mhz();
210            self.generate_sample();
211        }
212    }
213
214    fn generate_sample(&mut self) {
215        // Analog samples in range [-1, +1]
216        let channel_samples = [
217            self.dacs[0].digital_to_analog(self.pulse_1.sample()),
218            self.dacs[1].digital_to_analog(self.pulse_2.sample()),
219            self.dacs[2].digital_to_analog(self.wavetable.sample()),
220            self.dacs[3].digital_to_analog(self.noise.sample()),
221        ];
222
223        // Sum channel samples; now in range [-4, +4]
224        let mut sample_l = (0..4)
225            .map(|i| channel_samples[i] * f64::from(self.stereo_control.left_channels[i]))
226            .sum::<f64>();
227        let mut sample_r = (0..4)
228            .map(|i| channel_samples[i] * f64::from(self.stereo_control.right_channels[i]))
229            .sum::<f64>();
230
231        // Apply volume multiplier (1-8); now in range [-32, +32]
232        sample_l *= f64::from(self.stereo_control.left_volume + 1);
233        sample_r *= f64::from(self.stereo_control.right_volume + 1);
234
235        // Normalize back from [-32, +32] to [-1, +1] range
236        // Additionally multiply by 0.5 because otherwise sound is way too loud
237        sample_l /= 64.0;
238        sample_r /= 64.0;
239
240        self.resampler.collect_sample(sample_l, sample_r);
241    }
242
243    fn clock_length_counters(&mut self) {
244        self.pulse_1.clock_length_counter();
245        self.pulse_2.clock_length_counter();
246        self.wavetable.clock_length_counter();
247        self.noise.clock_length_counter();
248    }
249
250    fn clock_envelopes(&mut self) {
251        self.pulse_1.clock_envelope();
252        self.pulse_2.clock_envelope();
253        self.noise.clock_envelope();
254    }
255
256    pub fn read_register(&self, address: u16) -> u8 {
257        log::trace!("APU read register {address:04X}");
258
259        match address & 0x7F {
260            0x10 => self.pulse_1.read_register_0(),
261            0x11 => self.pulse_1.read_register_1(),
262            0x12 => self.pulse_1.read_register_2(),
263            0x14 => self.pulse_1.read_register_4(),
264            0x16 => self.pulse_2.read_register_1(),
265            0x17 => self.pulse_2.read_register_2(),
266            0x19 => self.pulse_2.read_register_4(),
267            0x1A => self.wavetable.read_register_0(),
268            0x1C => self.wavetable.read_register_2(),
269            0x1E => self.wavetable.read_register_4(),
270            0x21 => self.noise.read_register_2(),
271            0x22 => self.noise.read_register_3(),
272            0x23 => self.noise.read_register_4(),
273            0x24 => self.stereo_control.read_volume(),
274            0x25 => self.stereo_control.read_enabled(),
275            0x26 => self.read_nr52(),
276            0x30..=0x3F => self.wavetable.read_ram(address),
277            _ => 0xFF,
278        }
279    }
280
281    fn read_nr52(&self) -> u8 {
282        0x70 | (u8::from(self.enabled) << 7)
283            | (u8::from(self.noise.enabled()) << 3)
284            | (u8::from(self.wavetable.enabled()) << 2)
285            | (u8::from(self.pulse_2.enabled()) << 1)
286            | u8::from(self.pulse_1.enabled())
287    }
288
289    pub fn read_pcm12(&self) -> u8 {
290        let ch1_sample = self.pulse_1.sample().unwrap_or(0);
291        let ch2_sample = self.pulse_2.sample().unwrap_or(0);
292        ch1_sample | (ch2_sample << 4)
293    }
294
295    pub fn read_pcm34(&self) -> u8 {
296        let ch3_sample = self.wavetable.sample().unwrap_or(0);
297        let ch4_sample = self.noise.sample().unwrap_or(0);
298        ch3_sample | (ch4_sample << 4)
299    }
300
301    pub fn write_register(&mut self, address: u16, value: u8) {
302        log::trace!("APU write register {address:04X} {value:02X}");
303
304        if !self.enabled && address != 0xFF26 && !(0xFF30..0xFF40).contains(&address) {
305            // When APU is disabled, writes are only allowed to NR52 and wavetable RAM
306            // On DMG, writes to length counters are allowed while the APU is disabled
307            if self.hardware_mode == HardwareMode::Dmg {
308                match address & 0x7F {
309                    0x11 => self.pulse_1.write_register_1(value, false),
310                    0x16 => self.pulse_2.write_register_1(value, false),
311                    0x1B => self.wavetable.write_register_1(value),
312                    0x20 => self.noise.write_register_1(value),
313                    _ => {}
314                }
315            }
316
317            return;
318        }
319
320        match address & 0x7F {
321            0x10 => self.pulse_1.write_register_0(value),
322            0x11 => self.pulse_1.write_register_1(value, self.enabled),
323            0x12 => self.pulse_1.write_register_2(value),
324            0x13 => self.pulse_1.write_register_3(value),
325            0x14 => self.pulse_1.write_register_4(value, self.frame_sequencer_step),
326            0x16 => self.pulse_2.write_register_1(value, self.enabled),
327            0x17 => self.pulse_2.write_register_2(value),
328            0x18 => self.pulse_2.write_register_3(value),
329            0x19 => self.pulse_2.write_register_4(value, self.frame_sequencer_step),
330            0x1A => self.wavetable.write_register_0(value),
331            0x1B => self.wavetable.write_register_1(value),
332            0x1C => self.wavetable.write_register_2(value),
333            0x1D => self.wavetable.write_register_3(value),
334            0x1E => self.wavetable.write_register_4(value, self.frame_sequencer_step),
335            0x20 => self.noise.write_register_1(value),
336            0x21 => self.noise.write_register_2(value),
337            0x22 => self.noise.write_register_3(value),
338            0x23 => self.noise.write_register_4(value, self.frame_sequencer_step),
339            0x24 => self.stereo_control.write_volume(value),
340            0x25 => self.stereo_control.write_enabled(value),
341            0x26 => self.write_nr52(value),
342            0x30..=0x3F => self.wavetable.write_ram(address, value),
343            _ => {}
344        }
345    }
346
347    fn write_nr52(&mut self, value: u8) {
348        // NR52: APU control
349        let prev_enabled = self.enabled;
350        self.enabled = value.bit(7);
351
352        if prev_enabled && !self.enabled {
353            // Reset all channel and register state
354            self.pulse_1 = PulseChannel::new();
355            self.pulse_2 = PulseChannel::new();
356            self.wavetable.reset(self.hardware_mode);
357            self.noise = NoiseChannel::new();
358            self.stereo_control = StereoControl::zero();
359        } else if !prev_enabled && self.enabled {
360            // Reset frame sequencer step when APU is re-enabled
361            self.frame_sequencer_step = 7;
362        }
363
364        log::trace!("NR52 write, APU enabled: {}", self.enabled);
365    }
366
367    pub fn drain_samples_into<A: AudioOutput>(
368        &mut self,
369        audio_output: &mut A,
370    ) -> Result<(), A::Err> {
371        self.resampler.output_samples(audio_output)
372    }
373
374    pub fn reload_config(&mut self, config: GameBoyEmulatorConfig) {
375        self.resampler.reload_config(&config);
376    }
377
378    pub fn update_output_frequency(&mut self, output_frequency: u64) {
379        self.resampler.update_output_frequency(output_frequency);
380    }
381}