Trying to figure this audio stuff out
This commit is contained in:
parent
807d65ca53
commit
9ddd8ac21c
@ -2,7 +2,6 @@ use super::mbc::mbc::MBC;
|
||||
|
||||
#[derive(Debug,PartialEq)]
|
||||
enum MemoryBankControllerType {
|
||||
None,
|
||||
MBC1,
|
||||
MBC2,
|
||||
MBC3,
|
||||
@ -24,11 +23,11 @@ pub struct Cartridge {
|
||||
|
||||
impl Cartridge {
|
||||
pub fn new(rom: Box<[u8]>, save_file: Option<String>) -> Cartridge {
|
||||
let mbc_type: MemoryBankControllerType = match rom[0x0147] {
|
||||
0x00 | 0x08 ... 0x09 => MemoryBankControllerType::None,
|
||||
0x01 ... 0x03 => MemoryBankControllerType::MBC1,
|
||||
0x05 ... 0x06 => MemoryBankControllerType::MBC2,
|
||||
0x0F ... 0x13 => MemoryBankControllerType::MBC3,
|
||||
let mbc_type = match rom[0x0147] {
|
||||
0x00 | 0x08 ... 0x09 => None,
|
||||
0x01 ... 0x03 => Some(MemoryBankControllerType::MBC1),
|
||||
0x05 ... 0x06 => Some(MemoryBankControllerType::MBC2),
|
||||
0x0F ... 0x13 => Some(MemoryBankControllerType::MBC3),
|
||||
// 0xFF => MemoryBankControllerType::HuC1,
|
||||
_ => panic!("Unsupported MBC type: {:02X}", rom[0x0147]),
|
||||
};
|
||||
@ -58,10 +57,10 @@ impl Cartridge {
|
||||
let ram = Cartridge::load_savefile(&save_file, ram_size);
|
||||
|
||||
let mbc: Box<super::mbc::mbc::MBC> = match mbc_type {
|
||||
MemoryBankControllerType::None => Box::new(super::mbc::mbc::NoMBC::new(rom, ram)),
|
||||
MemoryBankControllerType::MBC1 => Box::new(super::mbc::mbc1::MBC1::new(rom, ram)),
|
||||
MemoryBankControllerType::MBC2 => Box::new(super::mbc::mbc2::MBC2::new(rom, ram)),
|
||||
MemoryBankControllerType::MBC3 => Box::new(super::mbc::mbc3::MBC3::new(rom, ram)),
|
||||
None => Box::new(super::mbc::mbc::NoMBC::new(rom, ram)),
|
||||
Some(MemoryBankControllerType::MBC1) => Box::new(super::mbc::mbc1::MBC1::new(rom, ram)),
|
||||
Some(MemoryBankControllerType::MBC2) => Box::new(super::mbc::mbc2::MBC2::new(rom, ram)),
|
||||
Some(MemoryBankControllerType::MBC3) => Box::new(super::mbc::mbc3::MBC3::new(rom, ram)),
|
||||
};
|
||||
|
||||
Cartridge {
|
||||
@ -71,7 +70,6 @@ impl Cartridge {
|
||||
}
|
||||
|
||||
fn load_savefile(save_file: &Option<String>, ram_size: RamSize) -> Box<[u8]> {
|
||||
let old_data;
|
||||
let size = match ram_size {
|
||||
RamSize::None => 0,
|
||||
RamSize::Ram2KB => 2048,
|
||||
@ -81,22 +79,22 @@ impl Cartridge {
|
||||
|
||||
if let &Some(ref filename) = save_file {
|
||||
let data = super::read_file(&filename);
|
||||
if let Ok(success) = data {
|
||||
old_data = success
|
||||
if let Ok(data) = data {
|
||||
data
|
||||
} else {
|
||||
old_data = vec![0u8; size].into_boxed_slice();
|
||||
// Generate empty buffer
|
||||
println!("Warning: Could not open save file");
|
||||
vec![0u8; size].into_boxed_slice()
|
||||
}
|
||||
} else {
|
||||
old_data = vec![0u8; size].into_boxed_slice();
|
||||
vec![0u8; size].into_boxed_slice()
|
||||
}
|
||||
|
||||
old_data
|
||||
}
|
||||
|
||||
pub fn save(&self) {
|
||||
if let &Some(ref fil) = &self.savefile {
|
||||
if let Some(ref fil) = self.savefile {
|
||||
println!("Updating RAM dump");
|
||||
self.mbc.dump_ram(fil);
|
||||
println!("Ram dump updated.")
|
||||
} else {
|
||||
println!("Did not update ram dump");
|
||||
}
|
||||
|
||||
11
src/cpu.rs
11
src/cpu.rs
@ -102,7 +102,6 @@ impl CPU {
|
||||
|
||||
#[inline]
|
||||
fn adc_r(&mut self, val: u8) {
|
||||
// Passes the test
|
||||
let old: u8 = self.regs[REG_A];
|
||||
let mut new: u8 = old;
|
||||
let c: u8;
|
||||
@ -123,7 +122,6 @@ impl CPU {
|
||||
|
||||
#[inline]
|
||||
fn add_r(&mut self, val: u8) {
|
||||
// Passes the test
|
||||
let old: u8 = self.regs[REG_A];
|
||||
let new: u8 = old.wrapping_add(val);
|
||||
let carry: u16 = (old as u16) ^ (val as u16) ^ (new as u16);
|
||||
@ -137,7 +135,6 @@ impl CPU {
|
||||
|
||||
#[inline]
|
||||
fn sbc_r(&mut self, val: u8) {
|
||||
// Passes the test
|
||||
let old: u8 = self.regs[REG_A];
|
||||
let mut new: u8 = old as u8;
|
||||
let c: u8;
|
||||
@ -159,7 +156,6 @@ impl CPU {
|
||||
|
||||
#[inline]
|
||||
fn sub_r(&mut self, val: u8) {
|
||||
// Passes the test
|
||||
let old: u8 = self.regs[REG_A];
|
||||
let new: u8 = old.wrapping_sub(val);
|
||||
let carry: u16 = (old as u16) ^ (val as u16) ^ (new as u16);
|
||||
@ -173,7 +169,6 @@ impl CPU {
|
||||
|
||||
#[inline]
|
||||
fn cp_r(&mut self, val: u8) {
|
||||
// Passes the test
|
||||
let old: u8 = self.regs[REG_A];
|
||||
let new: u8 = old.wrapping_sub(val);
|
||||
let carry: u16 = (old as u16) ^ (val as u16) ^ (new as u16);
|
||||
@ -866,6 +861,7 @@ impl CPU {
|
||||
|
||||
pub fn run(&mut self) {
|
||||
loop {
|
||||
// Some attempt at limiting our speed
|
||||
let mut cycles: i32 = 0;
|
||||
let start = Instant::now();
|
||||
for _ in 0 .. 1000 {
|
||||
@ -877,8 +873,6 @@ impl CPU {
|
||||
let delta = gb_dur - our_dur;
|
||||
if delta > (20 * 238) { // We're at least 20 cycles faster.
|
||||
sleep(Duration::new(0, delta as u32));
|
||||
} else if delta < 0 {
|
||||
print!("-");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -889,6 +883,8 @@ impl CPU {
|
||||
let enabled = self.interconnect.read_byte(0xFFFF);
|
||||
let e_pending = pending & enabled;
|
||||
|
||||
// Handling interrupts. Do only execute the one with the highest
|
||||
// priority
|
||||
if e_pending & interconnect::INTERRUPT_DISPLAY_VBLANK > 0 {
|
||||
if execute {
|
||||
self.handle_interrupt(0x40, interconnect::INTERRUPT_DISPLAY_VBLANK);
|
||||
@ -1667,7 +1663,6 @@ impl CPU {
|
||||
16
|
||||
},
|
||||
0xFB => {
|
||||
// Enable interrupts - TODO
|
||||
if self.debug {
|
||||
println!("EI");
|
||||
}
|
||||
|
||||
@ -246,7 +246,7 @@ impl Display {
|
||||
#[inline]
|
||||
pub fn vblank_interrupt(&mut self) -> bool {
|
||||
// Returns whether or not a vblank interrupt should be done
|
||||
// Yes, this is polling, and yes, this sucks.\
|
||||
// Yes, this is polling, and yes, this sucks.
|
||||
if self.vblank_interrupt {
|
||||
self.vblank_interrupt = false;
|
||||
true
|
||||
|
||||
@ -133,6 +133,9 @@ impl Interconnect {
|
||||
pub fn tick(&mut self, cycles: u8) {
|
||||
self.display.tick(cycles as u16);
|
||||
self.timer.tick(cycles as u16);
|
||||
for _ in 0..cycles {
|
||||
self.sound.tick();
|
||||
}
|
||||
|
||||
if self.display.vblank_interrupt() {
|
||||
self.interrupt_request_flags |= INTERRUPT_DISPLAY_VBLANK;
|
||||
|
||||
@ -12,7 +12,7 @@ impl Serial {
|
||||
pub fn write_byte(&mut self, addr: u16, val: u8) {
|
||||
match addr {
|
||||
0xFF01 => {
|
||||
println!("Serial: Write {:02X}", val);
|
||||
// println!("Serial: Write {:02X}", val);
|
||||
self.data = val;
|
||||
}
|
||||
0xFF02 => self.control = val,
|
||||
|
||||
612
src/sound.rs
612
src/sound.rs
@ -1,17 +1,501 @@
|
||||
const TICK_RATE: usize = 4194304;
|
||||
const OUTPUT_SAMPLE_RATE: usize = 32768;
|
||||
const TICKS_PER_SAMPLE: usize = TICK_RATE / OUTPUT_SAMPLE_RATE;
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug)]
|
||||
enum EnvelopeDirection {
|
||||
Increase,
|
||||
Decrease
|
||||
}
|
||||
|
||||
#[derive(Debug,Clone)]
|
||||
struct VolumeEnvelope(u8);
|
||||
#[allow(dead_code)]
|
||||
impl VolumeEnvelope {
|
||||
fn initial_volume(&self) -> u8 {
|
||||
self.0 >> 4
|
||||
}
|
||||
|
||||
fn envelope_direction(&self) -> EnvelopeDirection {
|
||||
match self.0 & (1 << 3) {
|
||||
0 => EnvelopeDirection::Decrease,
|
||||
_ => EnvelopeDirection::Increase,
|
||||
}
|
||||
}
|
||||
|
||||
fn nr_of_envelope_sweep(&self) -> u8 {
|
||||
self.0 & 0x7
|
||||
}
|
||||
|
||||
fn set_nr_of_envelope_sweep(&mut self, nr: u8) {
|
||||
self.0 &= !0x7;
|
||||
self.0 |= nr & 0x7;
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u8> for VolumeEnvelope {
|
||||
fn from(val: u8) -> VolumeEnvelope {
|
||||
VolumeEnvelope(val)
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<u8> for VolumeEnvelope {
|
||||
fn into(self) -> u8 {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for VolumeEnvelope {
|
||||
fn default() -> VolumeEnvelope {
|
||||
VolumeEnvelope(0)
|
||||
}
|
||||
}
|
||||
|
||||
trait OutputChannel {
|
||||
fn sample(&mut self) -> i8;
|
||||
fn clock_length_counter(&mut self); // 256 Hz
|
||||
fn clock_volume_envelope(&mut self) -> Option<EnvelopeDirection>; // 64 Hz
|
||||
|
||||
// A square channel's frequency timer period is set to (2048-frequency)*4.
|
||||
// Four duty cycles are available, each waveform taking 8 frequency timer clocks to cycle through:
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum ChannelMode {
|
||||
CounterMode,
|
||||
ConsecutiveMode,
|
||||
}
|
||||
|
||||
impl Default for ChannelMode {
|
||||
fn default() -> Self {
|
||||
ChannelMode::CounterMode
|
||||
}
|
||||
}
|
||||
|
||||
// Tone & Sweep
|
||||
#[derive(Debug, Default)]
|
||||
struct Channel1 {
|
||||
// MMaped registers
|
||||
sweep_register: u8,
|
||||
sound_length: u8,
|
||||
volume_envelope: VolumeEnvelope,
|
||||
active_volume_envelope: VolumeEnvelope,
|
||||
frequency_low: u8,
|
||||
frequency_high: u8,
|
||||
|
||||
// Registeres used for sound generation
|
||||
current_phase: f32,
|
||||
// Depending on sound_length
|
||||
//sound_enabled: bool,
|
||||
// Current envelope volume
|
||||
envelope_volume: u8,
|
||||
current_mode: ChannelMode,
|
||||
}
|
||||
|
||||
impl OutputChannel for Channel1 {
|
||||
/*
|
||||
According to some specification page:
|
||||
gb = 2048 - (131072 / Hz)
|
||||
Hz = 131072 / (2048 - gb)
|
||||
*/
|
||||
fn sample(&mut self) -> i8 {
|
||||
// Right now just assume that we have 100% on time
|
||||
// I also don't know right now how to disable channel1 :(
|
||||
let freq = self.current_frequency();
|
||||
// sample rate 128? Dunno!
|
||||
self.current_phase += 1f32 / (2048f32 * TICKS_PER_SAMPLE as f32);
|
||||
let sample = 2.0 * 3.1415 * freq * self.current_phase;
|
||||
let volume = (127f32 * self.envelope_volume as f32 / 16f32) as i8;
|
||||
|
||||
if sample.sin() > 0f32 {
|
||||
volume
|
||||
} else {
|
||||
-1 * volume
|
||||
}
|
||||
|
||||
//(sample.sin() * volume as f32) as i8
|
||||
}
|
||||
|
||||
fn clock_length_counter(&mut self) {
|
||||
if self.frequency_high & (1 << 6) > 0 {
|
||||
// Use sound length
|
||||
let sound_length = self.sound_length & 0x3F;
|
||||
if sound_length > 0 {
|
||||
self.sound_length &= 0xC0;
|
||||
self.sound_length |= sound_length - 1;
|
||||
// self.sound_enabled = true;
|
||||
} else {
|
||||
// self.sound_enabled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
fn clock_volume_envelope(&mut self) -> Option<EnvelopeDirection> {
|
||||
if self.active_volume_envelope.nr_of_envelope_sweep() > 0 {
|
||||
let left = self.active_volume_envelope.nr_of_envelope_sweep();
|
||||
self.active_volume_envelope.set_nr_of_envelope_sweep(left - 1);
|
||||
match self.active_volume_envelope.envelope_direction() {
|
||||
EnvelopeDirection::Decrease => {
|
||||
if self.envelope_volume > 0 {
|
||||
self.envelope_volume -= 1;
|
||||
println!("CH1: Decreased envelope volume to {} (steps left: {})", self.envelope_volume, left-1);
|
||||
}
|
||||
},
|
||||
EnvelopeDirection::Increase => {
|
||||
if self.envelope_volume < 0xF {
|
||||
self.envelope_volume += 1;
|
||||
println!("CH1: Increased envelope volume to {}", self.envelope_volume);
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(self.active_volume_envelope.envelope_direction())
|
||||
} else {
|
||||
match self.current_mode {
|
||||
ChannelMode::CounterMode => {
|
||||
self.envelope_volume = 0;
|
||||
}
|
||||
ChannelMode::ConsecutiveMode => {
|
||||
|
||||
}
|
||||
};
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Channel1 {
|
||||
fn current_frequency(&self) -> f32 {
|
||||
let full_freq = ((self.frequency_high as u16 & 0x7) << 8) | self.frequency_low as u16;
|
||||
131072f32 / (2048f32 - full_freq as f32)
|
||||
}
|
||||
|
||||
fn write_byte(&mut self, addr: u16, val: u8) {
|
||||
match addr {
|
||||
0xFF10 => {
|
||||
println!("WARNING: Sound0 sweep not supported yet");
|
||||
self.sweep_register = val
|
||||
},
|
||||
0xFF11 => {
|
||||
// println!("Channel1: Sound length set to {} (wave pattern: {})", val & 0x3F, val >> 6);
|
||||
self.sound_length = val;
|
||||
},
|
||||
0xFF12 => {
|
||||
self.volume_envelope = val.into();
|
||||
},
|
||||
0xFF13 => self.frequency_low = val,
|
||||
0xFF14 => {
|
||||
self.frequency_high = val;
|
||||
if val & (1 << 7) > 0 {
|
||||
println!("CH1: started");
|
||||
self.active_volume_envelope = self.volume_envelope.clone();
|
||||
self.envelope_volume = self.active_volume_envelope.initial_volume();
|
||||
}
|
||||
|
||||
self.current_mode = match val & (1 << 6) {
|
||||
0 => ChannelMode::CounterMode,
|
||||
_ => ChannelMode::ConsecutiveMode,
|
||||
};
|
||||
|
||||
// self.dump();
|
||||
self.frequency_high &= 0x7;
|
||||
},
|
||||
_ => panic!("Invalid addr for channel1 write: {:04X}", addr),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_byte(&self, addr: u16) -> u8 {
|
||||
match addr {
|
||||
0xFF10 => self.sweep_register,
|
||||
0xFF11 => self.sound_length,
|
||||
0xFF12 => self.volume_envelope.0,
|
||||
// 0xFF13 => self.frequency_low, // R/O
|
||||
0xFF14 => self.frequency_high & (1 << 6), // Only one bit readable
|
||||
_ => panic!("Tried to read invalid register {:04X}", addr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Tone
|
||||
#[derive(Debug, Default)]
|
||||
struct Channel2 {
|
||||
sound_length: u8,
|
||||
volume_envelope: VolumeEnvelope,
|
||||
active_volume_envelope: VolumeEnvelope,
|
||||
frequency_low: u8,
|
||||
frequency_high: u8,
|
||||
|
||||
// Registeres used for sound generation
|
||||
current_phase: f32,
|
||||
// Depending on sound_length
|
||||
// sound_enabled: bool,
|
||||
// Current envelope volume
|
||||
envelope_volume: u8,
|
||||
current_mode: ChannelMode,
|
||||
}
|
||||
|
||||
impl OutputChannel for Channel2 {
|
||||
/*
|
||||
According to some specification page:
|
||||
gb = 2048 - (131072 / Hz)
|
||||
Hz = 131072 / (2048 - gb)
|
||||
*/
|
||||
fn sample(&mut self) -> i8 {
|
||||
// Right now just assume that we have 100% on time
|
||||
// I also don't know right now how to disable channel1 :(
|
||||
let freq = self.current_frequency();
|
||||
// sample rate 128? Dunno!
|
||||
self.current_phase += 1f32 / (2048f32 * TICKS_PER_SAMPLE as f32);
|
||||
let sample = 2.0 * 3.1415 * freq * self.current_phase;
|
||||
// let volume = (127f32 * self.envelope_volume as f32 / 16f32) as i8;
|
||||
|
||||
if sample.sin() > 0f32 {
|
||||
40
|
||||
} else {
|
||||
-40
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn clock_length_counter(&mut self) {
|
||||
if self.frequency_high & (1 << 6) > 0 {
|
||||
// Use sound length
|
||||
let sound_length = self.sound_length & 0x3F;
|
||||
if sound_length > 0 {
|
||||
self.sound_length &= 0xC0;
|
||||
self.sound_length |= sound_length - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
fn clock_volume_envelope(&mut self) -> Option<EnvelopeDirection> {
|
||||
if self.active_volume_envelope.nr_of_envelope_sweep() > 0 {
|
||||
let left = self.active_volume_envelope.nr_of_envelope_sweep();
|
||||
self.active_volume_envelope.set_nr_of_envelope_sweep(left - 1);
|
||||
match self.active_volume_envelope.envelope_direction() {
|
||||
EnvelopeDirection::Decrease => {
|
||||
if self.envelope_volume > 0 {
|
||||
self.envelope_volume -= 1;
|
||||
println!("CH2: Decreased envelope volume to {} (steps left: {})", self.envelope_volume, left-1);
|
||||
}
|
||||
},
|
||||
EnvelopeDirection::Increase => {
|
||||
if self.envelope_volume < 0xF {
|
||||
self.envelope_volume += 1;
|
||||
println!("CH2: Increased envelope volume to {}", self.envelope_volume);
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(self.active_volume_envelope.envelope_direction())
|
||||
} else {
|
||||
match self.current_mode {
|
||||
ChannelMode::CounterMode => {
|
||||
self.envelope_volume = 0;
|
||||
}
|
||||
ChannelMode::ConsecutiveMode => {
|
||||
|
||||
}
|
||||
};
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Channel2 {
|
||||
fn current_frequency(&self) -> f32 {
|
||||
let full_freq = ((self.frequency_high as u16 & 0x7) << 8) | self.frequency_low as u16;
|
||||
131072f32 / (2048f32 - full_freq as f32)
|
||||
}
|
||||
|
||||
fn write_byte(&mut self, addr: u16, val: u8) {
|
||||
match addr {
|
||||
0xFF16 => self.sound_length = val,
|
||||
0xFF17 => {
|
||||
self.volume_envelope = val.into();
|
||||
},
|
||||
0xFF18 => self.frequency_low = val,
|
||||
0xFF19 => {
|
||||
self.frequency_high = val;
|
||||
if self.frequency_high & 0x80 == 0x80 {
|
||||
println!("CH2: Started");
|
||||
self.active_volume_envelope = self.volume_envelope.clone();
|
||||
self.envelope_volume = self.active_volume_envelope.initial_volume();
|
||||
}
|
||||
|
||||
self.current_mode = match val & (1 << 6) {
|
||||
0 => ChannelMode::CounterMode,
|
||||
_ => ChannelMode::ConsecutiveMode,
|
||||
};
|
||||
self.frequency_high &= 0x7;
|
||||
},
|
||||
_ => panic!("Invalid addr for channel2 write: {:04X}", addr),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_byte(&self, addr: u16) -> u8 {
|
||||
match addr {
|
||||
0xFF16 => self.sound_length,
|
||||
0xFF17 => self.volume_envelope.0,
|
||||
// 0xFF18 => self.frequency_low, // R/O
|
||||
0xFF19 => self.frequency_high & (1 << 6), // Only one bit readable
|
||||
_ => panic!("Tried to read invalid register {:04X}", addr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Wave output
|
||||
#[derive(Debug, Default)]
|
||||
struct Channel3 {
|
||||
enable: u8,
|
||||
sound_length: u8,
|
||||
output_level: u8,
|
||||
frequency_low: u8,
|
||||
frequency_high: u8,
|
||||
|
||||
wave_pattern_data: [u8; 16],
|
||||
|
||||
// Registeres used for sound generation
|
||||
ticks_since_enable: usize,
|
||||
|
||||
current_pattern_offset: usize,
|
||||
}
|
||||
|
||||
impl OutputChannel for Channel3 {
|
||||
fn sample(&mut self) -> i8 {
|
||||
if self.enable > 0 {
|
||||
self.ticks_since_enable += 1;
|
||||
let val = self.wave_pattern_data[self.current_pattern_offset/2];
|
||||
let samp = if val & 1 == 0 {
|
||||
val >> 4
|
||||
} else {
|
||||
val & 0x0F
|
||||
};
|
||||
|
||||
let freq = self.current_frequency();
|
||||
if (TICK_RATE as f32 / self.ticks_since_enable as f32) < (freq as f32) {
|
||||
self.current_pattern_offset += 1;
|
||||
self.current_pattern_offset %= 32;
|
||||
self.ticks_since_enable = 0;
|
||||
}
|
||||
|
||||
let samp = match self.output_level >> 5 {
|
||||
0 => 0,
|
||||
1 => samp,
|
||||
2 => samp >> 1,
|
||||
_ => samp >> 2,
|
||||
};
|
||||
|
||||
let samp = samp << 4;
|
||||
|
||||
samp as i8
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
fn clock_length_counter(&mut self) {
|
||||
if self.frequency_high & (1 << 6) > 0 {
|
||||
// Use sound length
|
||||
let sound_length = self.sound_length & 0x3F;
|
||||
if sound_length > 0 {
|
||||
self.sound_length &= 0xC0;
|
||||
self.sound_length |= sound_length - 1;
|
||||
// self.sound_enabled = true;
|
||||
} else {
|
||||
// self.sound_enabled = false;
|
||||
self.enable = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
fn clock_volume_envelope(&mut self) -> Option<EnvelopeDirection> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl Channel3 {
|
||||
fn current_frequency(&self) -> f32 {
|
||||
let full_freq = ((self.frequency_high as u16 & 0x7) << 8) | self.frequency_low as u16;
|
||||
(2048f32 - full_freq as f32) * 2f32
|
||||
}
|
||||
|
||||
fn write_byte(&mut self, addr: u16, val: u8) {
|
||||
match addr {
|
||||
0xFF1A => {self.enable = val; self.ticks_since_enable = 0},
|
||||
0xFF1B => self.sound_length = val,
|
||||
0xFF1C => self.output_level = val,
|
||||
0xFF1D => self.frequency_low = val,
|
||||
0xFF1E => {
|
||||
self.frequency_high = val;
|
||||
// TODO: Check for start
|
||||
println!("Starting sound3?");
|
||||
self.frequency_high &= 0x7;
|
||||
},
|
||||
0xFF30...0xFF3F => {
|
||||
self.wave_pattern_data[addr as usize - 0xFF30] = val;
|
||||
}
|
||||
_ => panic!("Invalid addr for channel3 write: {:04X}", addr),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_byte(&self, addr: u16) -> u8 {
|
||||
match addr {
|
||||
0xFF1A => self.enable,
|
||||
0xFF1B => self.sound_length,
|
||||
0xFF1C => self.output_level,
|
||||
//0xFF1D => self.frequency_low,
|
||||
0xFF1E => self.frequency_high & 1 << 6,
|
||||
0xFF30...0xFF3F => {
|
||||
self.wave_pattern_data[addr as usize - 0xFF30]
|
||||
}
|
||||
_ => panic!("Tried to read invalid register {:04X}", addr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Noise output
|
||||
#[derive(Debug, Default)]
|
||||
struct Channel4 {
|
||||
sound_length: u8,
|
||||
volume_envelope: VolumeEnvelope,
|
||||
polynominal_counter: u8,
|
||||
counter_mode: u8,
|
||||
}
|
||||
|
||||
impl Channel4 {
|
||||
fn write_byte(&mut self, addr: u16, val: u8) {
|
||||
match addr {
|
||||
0xFF20 => self.sound_length = val,
|
||||
0xFF21 => self.volume_envelope = val.into(),
|
||||
0xFF22 => self.polynominal_counter = val,
|
||||
0xFF23 => self.counter_mode = val,
|
||||
_ => panic!("Invalid addr for channel4 write: {:04X}", addr),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_byte(&self, addr: u16) -> u8 {
|
||||
match addr {
|
||||
0xFF20 => self.sound_length,
|
||||
0xFF21 => self.volume_envelope.0,
|
||||
0xFF22 => self.polynominal_counter,
|
||||
0xFF23 => self.counter_mode,
|
||||
_ => panic!("Tried to read invalid register {:04X}", addr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct Sound {
|
||||
enabled: u8,
|
||||
sound_length_1: u8,
|
||||
sound_control_1: u8,
|
||||
|
||||
channel1: Channel1,
|
||||
channel2: Channel2,
|
||||
channel3: Channel3,
|
||||
channel4: Channel4,
|
||||
|
||||
sound_channel_volume_control: u8,
|
||||
sound_output_terminal_selector: u8,
|
||||
sound_freq_low: u8,
|
||||
sound_freq_high: u8,
|
||||
|
||||
channel2_sound_length: u8,
|
||||
channel2_volume: u8,
|
||||
channel2_freq_lo: u8,
|
||||
channel2_freq_hi: u8,
|
||||
ticks: usize,
|
||||
}
|
||||
|
||||
impl Sound {
|
||||
@ -19,42 +503,114 @@ impl Sound {
|
||||
Sound::default()
|
||||
}
|
||||
|
||||
pub fn write_byte(&mut self, addr: u16, val: u8) {
|
||||
match addr {
|
||||
0xFF11 => self.sound_length_1 = val,
|
||||
0xFF12 => self.sound_control_1 = val,
|
||||
0xFF13 => self.sound_freq_low = val,
|
||||
0xFF14 => self.sound_freq_high = val,
|
||||
pub fn tick(&mut self) {
|
||||
self.ticks += 1;
|
||||
// Every 64 Hz volume envelope => all 65536 ticks
|
||||
// Every 256 Hz length check => all 16384 ticks
|
||||
|
||||
0xFF16 => self.channel2_sound_length = val,
|
||||
0xFF17 => self.channel2_volume = val,
|
||||
0xFF18 => self.channel2_freq_lo = val,
|
||||
0xFF19 => self.channel2_freq_hi = val,
|
||||
if self.ticks % 65536 == 0 {
|
||||
self.channel1.clock_volume_envelope();
|
||||
self.channel2.clock_volume_envelope();
|
||||
}
|
||||
|
||||
if self.ticks % 16384 == 0 {
|
||||
self.channel1.clock_length_counter();
|
||||
self.channel2.clock_length_counter();
|
||||
self.channel3.clock_length_counter();
|
||||
}
|
||||
|
||||
// How high is our rate? 32768?
|
||||
if self.ticks % TICKS_PER_SAMPLE == 0 {
|
||||
// Mix channels.
|
||||
let mut s01: i16 = 0;
|
||||
let mut s02: i16 = 0;
|
||||
|
||||
let s01_volume = self.sound_channel_volume_control & 7;
|
||||
let s02_volume = (self.sound_channel_volume_control >> 4) & 7;
|
||||
|
||||
// Take samples from the channels
|
||||
let c1_sample = self.channel1.sample();
|
||||
let c2_sample = self.channel2.sample();
|
||||
// let c3_sample = self.channel3.sample();
|
||||
// let c4_sample = self.channel4.sample();
|
||||
|
||||
//let c1_sample = 0;
|
||||
//let c2_sample = 0;
|
||||
let c3_sample = 0;
|
||||
|
||||
// Check S01
|
||||
if s01_volume > 0 {
|
||||
if self.sound_output_terminal_selector & 1 > 0 {
|
||||
// Output Channel1
|
||||
s01 += c1_sample as _;
|
||||
}
|
||||
if self.sound_output_terminal_selector & 2 > 0 && false {
|
||||
// Output Channel2
|
||||
s01 += c2_sample as _;
|
||||
}
|
||||
if self.sound_output_terminal_selector & 4 > 0 {
|
||||
// Output Channel3
|
||||
s01 += c3_sample as _;
|
||||
}
|
||||
if self.sound_output_terminal_selector & 8 > 0 {
|
||||
// Output Channel4
|
||||
}
|
||||
}
|
||||
|
||||
if s02_volume > 0 {
|
||||
if self.sound_output_terminal_selector & 0x10 > 0 && false {
|
||||
// Output Channel1
|
||||
s02 += c1_sample as _;
|
||||
}
|
||||
if self.sound_output_terminal_selector & 0x20 > 0 {
|
||||
// Output Channel2
|
||||
s02 += c2_sample as _;
|
||||
}
|
||||
if self.sound_output_terminal_selector & 0x40 > 0 {
|
||||
// Output Channel3
|
||||
s02 += c3_sample as _;
|
||||
}
|
||||
if self.sound_output_terminal_selector & 0x80 > 0 {
|
||||
// Output Channel4
|
||||
}
|
||||
}
|
||||
|
||||
println!("S:{}:{}", s01 >> 0, s02 >> 0);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_byte(&mut self, addr: u16, val: u8) {
|
||||
println!("Snd: {:04X} = {:02X} ({:08b})", addr, val, val);
|
||||
match addr {
|
||||
0xFF10...0xFF14 => self.channel1.write_byte(addr, val),
|
||||
0xFF16...0xFF19 => self.channel2.write_byte(addr, val),
|
||||
0xFF1A...0xFF1E => self.channel3.write_byte(addr, val),
|
||||
0xFF20...0xFF23 => self.channel4.write_byte(addr, val),
|
||||
|
||||
0xFF24 => self.sound_channel_volume_control = val,
|
||||
0xFF25 => self.sound_output_terminal_selector = val,
|
||||
0xFF26 => self.enabled = val,
|
||||
0xFF30...0xFF3F => self.channel3.write_byte(addr, val),
|
||||
|
||||
_ => {
|
||||
// println!("Sound: Write {:02X} to {:04X} unsupported", val, addr);
|
||||
panic!("Sound: Write {:02X} to {:04X} unsupported", val, addr);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_byte(&self, addr: u16) -> u8 {
|
||||
println!("RD {:04X}", addr);
|
||||
match addr {
|
||||
0xFF11 => self.sound_length_1,
|
||||
0xFF12 => self.sound_control_1,
|
||||
0xFF13 => self.sound_freq_low,
|
||||
0xFF14 => self.sound_freq_high,
|
||||
|
||||
0xFF16 => self.channel2_sound_length,
|
||||
0xFF17 => self.channel2_volume,
|
||||
0xFF18 => self.channel2_freq_lo,
|
||||
0xFF19 => self.channel2_freq_hi,
|
||||
0xFF10...0xFF14 => self.channel1.read_byte(addr),
|
||||
0xFF16...0xFF19 => self.channel2.read_byte(addr),
|
||||
0xFF1A...0xFF1E => self.channel3.read_byte(addr),
|
||||
0xFF20...0xFF23 => self.channel4.read_byte(addr),
|
||||
|
||||
0xFF24 => self.sound_channel_volume_control,
|
||||
0xFF25 => self.sound_output_terminal_selector,
|
||||
0xFF26 => self.enabled,
|
||||
0xFF30...0xFF3F => self.channel3.read_byte(addr),
|
||||
|
||||
_ => panic!("Sound: Read from {:04X} unsupported", addr),
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user