Skip to content
Snippets Groups Projects
apu.rs 31.2 KiB
Newer Older
use std::collections::VecDeque;

use crate::{gb::GameBoy, warnln};

const DUTY_TABLE: [[u8; 8]; 4] = [
    [0, 0, 0, 0, 0, 0, 0, 1],
    [1, 0, 0, 0, 0, 0, 0, 1],
    [1, 0, 0, 0, 0, 1, 1, 1],
    [0, 1, 1, 1, 1, 1, 1, 0],
];

const CH4_DIVISORS: [u8; 8] = [8, 16, 32, 48, 64, 80, 96, 112];

pub enum Channel {
    Ch1,
    Ch2,
    Ch3,
    Ch4,
}

pub struct Apu {
    ch1_envelope_sequence: u8,
    ch1_envelope_enabled: bool,
    ch1_sweep_sequence: u8,
    ch1_sweep_slope: u8,
    ch1_sweep_increase: bool,
    ch1_sweep_pace: u8,
    ch1_length_timer: u8,
    ch1_wave_duty: u8,
    ch1_pace: u8,
    ch1_direction: u8,
    ch1_volume: u8,
    ch1_wave_length: u16,
    ch1_length_stop: bool,
    ch1_enabled: bool,

    ch2_envelope_sequence: u8,
    ch2_envelope_enabled: bool,
    ch2_length_timer: u8,
    ch2_wave_duty: u8,
    ch2_pace: u8,
    ch2_direction: u8,
    ch2_volume: u8,
    ch2_wave_length: u16,
    ch2_length_stop: bool,
    ch2_enabled: bool,
    ch3_position: u8,
    ch3_output: u8,
    ch3_dac: bool,
    ch3_length_timer: u8,
    ch3_output_level: u8,
    ch3_wave_length: u16,
    ch3_length_stop: bool,
    ch3_enabled: bool,

    ch4_timer: i32,
    ch4_envelope_sequence: u8,
    ch4_envelope_enabled: bool,
    ch4_output: u8,
    ch4_length_timer: u8,
    ch4_pace: u8,
    ch4_direction: u8,
    ch4_volume: u8,
    ch4_divisor: u8,
    ch4_width_mode: bool,
    ch4_clock_shift: u8,
    ch4_lfsr: u16,
    ch4_length_stop: bool,
    ch4_enabled: bool,

    right_enabled: bool,
    left_enabled: bool,
    sound_enabled: bool,

    ch1_out_enabled: bool,
    ch2_out_enabled: bool,
    ch3_out_enabled: bool,
    ch4_out_enabled: bool,
    wave_ram: [u8; 16],
    sequencer: u16,
    sequencer_step: u8,
    output_timer: i16,
    audio_buffer: VecDeque<u8>,
    audio_buffer_max: usize,

    clock_freq: u32,
    pub fn new(sampling_rate: u16, buffer_size: f32, clock_freq: u32) -> Self {
            ch1_timer: 0,
            ch1_sequence: 0,
            ch1_envelope_sequence: 0,
            ch1_envelope_enabled: false,
            ch1_sweep_sequence: 0,
            ch1_sweep_slope: 0x0,
            ch1_sweep_increase: false,
            ch1_sweep_pace: 0x0,
            ch1_length_timer: 0x0,
            ch1_wave_duty: 0x0,
            ch1_pace: 0x0,
            ch1_direction: 0x0,
            ch1_volume: 0x0,
            ch1_wave_length: 0x0,
            ch1_length_stop: false,
            ch1_enabled: false,

            ch2_timer: 0,
            ch2_sequence: 0,
            ch2_envelope_sequence: 0,
            ch2_envelope_enabled: false,
            ch2_length_timer: 0x0,
            ch2_wave_duty: 0x0,
            ch2_pace: 0x0,
            ch2_direction: 0x0,
            ch2_volume: 0x0,
            ch2_wave_length: 0x0,
            ch2_length_stop: false,
            ch2_enabled: false,
            ch3_timer: 0,
            ch3_position: 0,
            ch3_output: 0,
            ch3_dac: false,
            ch3_length_timer: 0x0,
            ch3_output_level: 0x0,
            ch3_wave_length: 0x0,
            ch3_length_stop: false,
            ch3_enabled: false,

            ch4_envelope_sequence: 0,
            ch4_envelope_enabled: false,
            ch4_output: 0,
            ch4_length_timer: 0x0,
            ch4_pace: 0x0,
            ch4_direction: 0x0,
            ch4_volume: 0x0,
            ch4_divisor: 0x0,
            ch4_width_mode: false,
            ch4_clock_shift: 0x0,
            ch4_lfsr: 0x0,
            ch4_length_stop: false,
            ch4_enabled: false,

            left_enabled: true,
            right_enabled: true,
            sound_enabled: true,
            ch1_out_enabled: true,
            ch2_out_enabled: true,
            ch3_out_enabled: true,
            ch4_out_enabled: true,
            /// The RAM that is used to sore the wave information
            /// to be used in channel 3 audio
            wave_ram: [0u8; 16],
            /// The rate at which audio samples are going to be
            /// taken, ideally this value should be aligned with
            /// the sampling rate of the output device. A typical
            /// sampling rate would be of 44.1kHz.
            sampling_rate,

            /// Internal sequencer counter that runs at 512Hz
            /// used for the activation of the tick actions.
            sequencer: 0,
            sequencer_step: 0,
            audio_buffer: VecDeque::with_capacity(
                (sampling_rate as f32 * buffer_size) as usize * 2,
            audio_buffer_max: (sampling_rate as f32 * buffer_size) as usize * 2,
João Magalhães's avatar
João Magalhães committed
            clock_freq,
    pub fn reset(&mut self) {
        self.ch1_timer = 0;
        self.ch1_sequence = 0;
        self.ch1_envelope_sequence = 0;
        self.ch1_envelope_enabled = false;
Loading
Loading full blame...