1use crate::HardwareMode; 2use crate::apu::components::{TimerTickEffect, WavetableLengthCounter, WavetableTimer}; 3use bincode::{Decode, Encode}; 4use jgenesis_common::num::GetBit; 5 6#[derive(Debug, Clone, Encode, Decode)] 7pub struct WavetableChannel { 8 ram: [u8; 16], 9 sample_buffer: u8, 10 timer: WavetableTimer, 11 length_counter: WavetableLengthCounter, 12 volume: u8, 13 channel_enabled: bool, 14 dac_enabled: bool, 15}
From https://gbdev.gg8.se/wiki/articles/Gameboy_sound_hardware#Power_Control
22const CGB_INITIAL_RAM: [u8; 16] = [ 23 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 24]; 25 26impl WavetableChannel { 27 pub fn new(hardware_mode: HardwareMode) -> Self { 28 Self { 29 ram: match hardware_mode { 30 HardwareMode::Dmg => DMG_INITIAL_RAM, 31 HardwareMode::Cgb => CGB_INITIAL_RAM, 32 }, 33 sample_buffer: 0, 34 timer: WavetableTimer::new(), 35 length_counter: WavetableLengthCounter::new(), 36 volume: 0, 37 channel_enabled: false, 38 dac_enabled: false, 39 } 40 } 41 42 pub fn read_ram(&self, address: u16) -> u8 { 43 // Reading from wavetable RAM while the channel is playing returns the contents of RAM at 44 // the current wave position rather than the requested address. Demotronic depends on this 45 // for its emulator check 46 // TODO on DMG this should only happen if the read occurs on specific cycles, otherwise it 47 // should return 0xFF 48 // TODO more accurate timing; this doesn't pass cgb_sound 49 if self.channel_enabled { 50 return self.ram[(self.timer.phase >> 1) as usize]; 51 } 52 53 self.ram[(address & 0xF) as usize] 54 } 55 56 pub fn write_ram(&mut self, address: u16, value: u8) { 57 self.ram[(address & 0xF) as usize] = value; 58 } 59 60 pub fn read_register_0(&self) -> u8 { 61 0x7F | (u8::from(self.dac_enabled) << 7) 62 } 63 64 pub fn write_register_0(&mut self, value: u8) { 65 // NR30: Custom wave DAC enabled 66 self.dac_enabled = value.bit(7); 67 68 if !self.dac_enabled { 69 self.channel_enabled = false; 70 } 71 72 log::trace!("NR30 write, DAC enabled: {}", self.dac_enabled); 73 } 74 75 pub fn write_register_1(&mut self, value: u8) { 76 // NR31: Custom wave length counter reload 77 self.length_counter.load(value); 78 79 log::trace!("NR31 write, length counter: {}", self.length_counter.counter); 80 } 81 82 pub fn read_register_2(&self) -> u8 { 83 0x9F | (self.volume << 5) 84 } 85 86 pub fn write_register_2(&mut self, value: u8) { 87 // NR32: Custom wave volume 88 self.volume = (value >> 5) & 0x03; 89 90 log::trace!("NR32 write, volume: {}", self.volume); 91 } 92 93 pub fn write_register_3(&mut self, value: u8) { 94 // NR33: Custom wave frequency low bits 95 self.timer.write_frequency_low(value); 96 97 log::trace!("NR33 write, timer frequency: {}", self.timer.frequency()); 98 } 99 100 pub fn read_register_4(&self) -> u8 { 101 0xBF | (u8::from(self.length_counter.enabled) << 6) 102 } 103 104 pub fn write_register_4(&mut self, value: u8, frame_sequencer_step: u8) { 105 // NR34: Custom wave frequency high bits + length counter enabled + trigger 106 self.timer.write_frequency_high(value); 107 self.length_counter.set_enabled( 108 value.bit(6), 109 frame_sequencer_step, 110 &mut self.channel_enabled, 111 ); 112 113 if value.bit(7) { 114 // Channel triggered 115 self.timer.trigger(); 116 self.timer.phase = 0; 117 118 self.length_counter.trigger(frame_sequencer_step); 119 120 self.channel_enabled = self.dac_enabled; 121 } 122 123 log::trace!("NR34 write"); 124 log::trace!(" Timer frequency: {}", self.timer.frequency()); 125 log::trace!(" Length counter enabled: {}", self.length_counter.enabled); 126 log::trace!(" Triggered: {}", value.bit(7)); 127 } 128 129 pub fn tick_2mhz(&mut self) { 130 if !self.channel_enabled { 131 return; 132 } 133 134 if self.timer.tick() == TimerTickEffect::Clocked { 135 self.sample_buffer = self.ram[(self.timer.phase >> 1) as usize]; 136 } 137 } 138 139 pub fn clock_length_counter(&mut self) { 140 let prev_enabled = self.channel_enabled; 141 self.length_counter.clock(&mut self.channel_enabled); 142 143 if prev_enabled && !self.channel_enabled { 144 // Explicitly clear the sample buffer when the length counter disables the channel. 145 // Necessary because the wavetable channel continues to output the current sample buffer 146 // when disabled, as long as the DAC is still enabled 147 self.sample_buffer = 0; 148 } 149 } 150 151 pub fn sample(&self) -> Option<u8> { 152 if !self.dac_enabled { 153 return None; 154 } 155 156 // A disabled wavetable channel with an enabled DAC outputs the current sample buffer, not 0! 157 // Some games depend on this, e.g. Cannon Fodder 158 159 if self.volume == 0 { 160 return Some(0); 161 } 162 163 // First sample in high nibble, second sample in low nibble 164 let sample = if !self.timer.phase.bit(0) { 165 self.sample_buffer >> 4 166 } else { 167 self.sample_buffer & 0xF 168 }; 169 Some(sample >> (self.volume - 1)) 170 } 171 172 pub fn enabled(&self) -> bool { 173 self.channel_enabled 174 } 175 176 pub fn reset(&mut self, hardware_mode: HardwareMode) { 177 *self = Self { ram: self.ram, ..Self::new(hardware_mode) }; 178 } 179}