use crate::bit_utils;
mod noise_channel;
mod pulse_channel;
mod wave_channel;
use self::noise_channel::NoiseChannel;
use self::pulse_channel::PulseChannel;
use self::wave_channel::WaveChannel;
const READ_BYTE_OR_MASKS: [u8; 23] = [
0x80, 0x3f, 0x00, 0xff, 0xbf, 0xff, 0x3f, 0x00, 0xff, 0xbf, 0x7f, 0xff, 0x9f, 0xff, 0xbf, 0xff,
0xff, 0x00, 0x00, 0xbf, 0x00, 0x00, 0x70,
];
const SAMPLE_SIZE: usize = 4096;
pub struct Sound {
wave_channel: WaveChannel,
pulse_channel_1: PulseChannel,
pulse_channel_2: PulseChannel,
noise_channel: NoiseChannel,
audio_buffer: [f32; SAMPLE_SIZE],
vin_l_enable: bool,
vin_l_volume: u8,
vin_r_enable: bool,
vin_r_volume: u8,
left_enables: [bool; 4],
right_enables: [bool; 4],
power_control: bool,
frame_sequence_count_down: i32,
frame_sequencer: u8,
down_sample_count: i32,
buffer_fill_amount: usize,
}
impl Sound {
pub fn new() -> Sound {
Sound {
wave_channel: WaveChannel::new(),
pulse_channel_1: PulseChannel::new(),
pulse_channel_2: PulseChannel::new(),
noise_channel: NoiseChannel::new(),
audio_buffer: [0.0; SAMPLE_SIZE],
vin_l_enable: false,
vin_l_volume: 0,
vin_r_enable: false,
vin_r_volume: 0,
left_enables: [false; 4],
right_enables: [false; 4],
power_control: false,
frame_sequence_count_down: 8192,
frame_sequencer: 0,
down_sample_count: 95,
buffer_fill_amount: 0,
}
}
pub fn step(&mut self, cycles: i32) -> bool {
let mut audio_buffer_full = false;
let mut cycles = cycles;
while cycles != 0 {
cycles -= 1;
self.frame_sequence_count_down -= 1;
if self.frame_sequence_count_down == 0 {
self.frame_sequence_count_down = 8192;
match self.frame_sequencer {
0 | 4 => {
self.pulse_channel_1.length_click();
self.pulse_channel_2.length_click();
self.wave_channel.length_click();
self.noise_channel.length_click();
}
2 | 6 => {
self.pulse_channel_1.sweep_click();
self.pulse_channel_1.length_click();
self.pulse_channel_2.length_click();
self.wave_channel.length_click();
self.noise_channel.length_click();
}
7 => {
self.pulse_channel_1.env_click();
self.pulse_channel_2.env_click();
self.noise_channel.env_click();
}
_ => (),
};
self.frame_sequencer += 1;
if self.frame_sequencer >= 8 {
self.frame_sequencer = 0;
}
}
self.pulse_channel_1.step();
self.pulse_channel_2.step();
self.wave_channel.step();
self.noise_channel.step();
self.down_sample_count -= 1;
if self.down_sample_count <= 0 {
self.down_sample_count = 95;
let mut bufferin_0 = 0.0;
let mut bufferin_1;
let volume = (128 * self.vin_l_volume as i32) / 7;
if self.left_enables[0] {
bufferin_1 = (self.pulse_channel_1.get_output_vol() as f32) / 100.0;
Sound::mix_audio(&mut bufferin_0, bufferin_1, volume);
}
if self.left_enables[1] {
bufferin_1 = (self.pulse_channel_2.get_output_vol() as f32) / 100.0;
Sound::mix_audio(&mut bufferin_0, bufferin_1, volume);
}
if self.left_enables[2] {
bufferin_1 = (self.wave_channel.get_output_vol() as f32) / 100.0;
Sound::mix_audio(&mut bufferin_0, bufferin_1, volume);
}
if self.left_enables[3] {
bufferin_1 = (self.noise_channel.get_output_vol() as f32) / 100.0;
Sound::mix_audio(&mut bufferin_0, bufferin_1, volume);
}
self.audio_buffer[self.buffer_fill_amount] = bufferin_0;
bufferin_0 = 0.0;
if self.right_enables[0] {
bufferin_1 = (self.pulse_channel_1.get_output_vol() as f32) / 100.0;
Sound::mix_audio(&mut bufferin_0, bufferin_1, volume);
}
if self.right_enables[1] {
bufferin_1 = (self.pulse_channel_2.get_output_vol() as f32) / 100.0;
Sound::mix_audio(&mut bufferin_0, bufferin_1, volume);
}
if self.right_enables[2] {
bufferin_1 = (self.wave_channel.get_output_vol() as f32) / 100.0;
Sound::mix_audio(&mut bufferin_0, bufferin_1, volume);
}
if self.right_enables[3] {
bufferin_1 = (self.noise_channel.get_output_vol() as f32) / 100.0;
Sound::mix_audio(&mut bufferin_0, bufferin_1, volume);
}
self.audio_buffer[self.buffer_fill_amount + 1] = bufferin_0;
self.buffer_fill_amount += 2;
}
if self.buffer_fill_amount >= SAMPLE_SIZE {
self.buffer_fill_amount = 0;
audio_buffer_full = true;
break;
}
}
audio_buffer_full
}
fn mix_audio(dst: &mut f32, src: f32, volume: i32) {
let fmax_volume = 1.0f32 / 128f32;
let fvolume = volume as f32;
let max_audioval = std::f32::MAX as f64;
let min_audioval = std::f32::MIN as f64;
let src1 = src * fvolume * fmax_volume;
let src2 = *dst;
let mut dst_sample = src1 as f64 + src2 as f64;
if dst_sample > max_audioval {
dst_sample = max_audioval;
} else if dst_sample < min_audioval {
dst_sample = min_audioval;
}
*dst = dst_sample as f32;
}
pub fn read_byte(&self, address: u16) -> u8 {
let value = match address {
0xFF10..=0xFF14 => self.pulse_channel_1.read_byte(address),
0xFF15 => 0,
0xFF16..=0xFF19 => self.pulse_channel_2.read_byte(address),
0xFF1A..=0xFF1E => self.wave_channel.read_byte(address),
0xFF1F..=0xFF23 => self.noise_channel.read_byte(address),
0xFF24 => {
let vin_l_enable = if self.vin_l_enable { 1 } else { 0 };
let vin_r_enable = if self.vin_r_enable { 1 } else { 0 };
(vin_l_enable << 7)
| (self.vin_l_volume << 4)
| (vin_r_enable << 3)
| self.vin_r_volume
}
0xFF25 => {
let mut value = 0;
for i in 0..4 {
value |= if self.right_enables[i] { 1 << i } else { 0 };
}
for i in 0..4 {
value |= if self.left_enables[i] {
1 << (i + 4)
} else {
0
};
}
value
}
0xFF26 => {
let mut value = 0;
value |= if self.power_control { 1 } else { 0 } << 7;
value |= if self.pulse_channel_1.get_status() {
1
} else {
0
};
value |= if self.pulse_channel_2.get_status() {
1
} else {
0
} << 1;
value |= if self.wave_channel.get_status() { 1 } else { 0 } << 2;
value |= if self.noise_channel.get_status() {
1
} else {
0
} << 3;
value
}
0xFF27..=0xFF2F => 0xFF,
0xFF30..=0xFF3F => self.wave_channel.read_byte(address),
_ => panic!("unknown address: {:04X}", address),
};
if address >= 0xFF10 && address < 0xFF27 {
value | READ_BYTE_OR_MASKS[(address - 0xFF10) as usize]
} else {
value
}
}
pub fn write_byte(&mut self, address: u16, value: u8) {
if !self.power_control && address != 0xFF26 && address < 0xFF30 {
return;
}
match address {
0xFF10..=0xFF14 => self.pulse_channel_1.write_byte(address, value),
0xFF15 => (),
0xFF16..=0xFF19 => self.pulse_channel_2.write_byte(address, value),
0xFF1A..=0xFF1E => self.wave_channel.write_byte(address, value),
0xFF1F..=0xFF23 => self.noise_channel.write_byte(address, value),
0xFF24 => {
self.vin_l_enable = bit_utils::is_set(value, 7);
self.vin_l_volume = (value >> 4) & 0x7;
self.vin_r_enable = bit_utils::is_set(value, 3);
self.vin_r_volume = value & 0x7;
}
0xFF25 => {
for i in 0..4 {
self.right_enables[i] = bit_utils::is_set(value, i as u8);
}
for i in 0..4 {
self.left_enables[i] = bit_utils::is_set(value, i as u8 + 4);
}
}
0xFF26 => {
if !bit_utils::is_set(value, 7) {
for i in 0xFF10..=0xFF25 {
self.write_byte(i, 0);
}
self.pulse_channel_1.reset_length_counter();
self.pulse_channel_2.reset_length_counter();
self.wave_channel.reset_length_counter();
self.noise_channel.reset_length_counter();
self.power_control = false;
} else if !self.power_control {
self.frame_sequencer = 0;
for i in 0xFF30..=0xFF3F {
self.wave_channel.write_byte(i, 0);
}
self.power_control = true;
}
}
0xFF27..=0xFF2F => (),
0xFF30..=0xFF3F => self.wave_channel.write_byte(address, value),
_ => panic!("unknown address: {:04X}", address),
}
}
pub fn get_audio_buffer(&self) -> &[f32] {
self.audio_buffer.as_ref()
}
}
impl Default for Sound {
fn default() -> Sound {
Sound::new()
}
}