#![allow(dead_code)]
use mos6502;
pub trait Speaker {
fn queue(&mut self, sample: u16);
fn push(&mut self);
}
const CPU_SAMPLE_FREQ: u32 = 240;
pub const AUDIO_SAMPLE_FREQ: u32 = 44100;
const LEN_TABLE: [u8; 32] = [
10, 254, 20, 2, 40, 4, 80, 6, 160, 8, 60, 10, 14, 12, 26, 14,
12, 16, 24, 18, 48, 20, 96, 22, 192, 24, 72, 26, 16, 28, 32, 30,
];
const DUTY_TABLE: [u8; 4] = [
0b00000010,
0b00000110,
0b00011110,
0b11111001,
];
const PULSE_TABLE: [u16; 31] = [
0x0000, 0x02f8, 0x05df, 0x08b4, 0x0b78, 0x0e2b,
0x10cf, 0x1363, 0x15e9, 0x1860, 0x1ac9, 0x1d25,
0x1f75, 0x21b7, 0x23ee, 0x2618, 0x2837, 0x2a4c,
0x2c55, 0x2e54, 0x3049, 0x3234, 0x3416, 0x35ee,
0x37be, 0x3985, 0x3b43, 0x3cf9, 0x3ea7, 0x404d,
0x41ec
];
const TND_TABLE: [u16; 203] = [
0x0000, 0x01b7, 0x036a, 0x051a, 0x06c6, 0x086f,
0x0a15, 0x0bb7, 0x0d56, 0x0ef2, 0x108a, 0x121f,
0x13b1, 0x1540, 0x16cc, 0x1855, 0x19da, 0x1b5d,
0x1cdd, 0x1e59, 0x1fd3, 0x214a, 0x22be, 0x2430,
0x259e, 0x270a, 0x2874, 0x29da, 0x2b3e, 0x2c9f,
0x2dfe, 0x2f5a, 0x30b4, 0x320b, 0x335f, 0x34b2,
0x3601, 0x374f, 0x389a, 0x39e2, 0x3b29, 0x3c6d,
0x3dae, 0x3eee, 0x402b, 0x4166, 0x429f, 0x43d6,
0x450a, 0x463d, 0x476d, 0x489c, 0x49c8, 0x4af2,
0x4c1b, 0x4d41, 0x4e65, 0x4f87, 0x50a8, 0x51c6,
0x52e3, 0x53fe, 0x5517, 0x562e, 0x5743, 0x5856,
0x5968, 0x5a78, 0x5b86, 0x5c93, 0x5d9d, 0x5ea6,
0x5fae, 0x60b3, 0x61b7, 0x62ba, 0x63bb, 0x64ba,
0x65b7, 0x66b3, 0x67ae, 0x68a7, 0x699e, 0x6a94,
0x6b88, 0x6c7b, 0x6d6d, 0x6e5d, 0x6f4b, 0x7038,
0x7124, 0x720e, 0x72f7, 0x73de, 0x74c4, 0x75a9,
0x768c, 0x776e, 0x784f, 0x792e, 0x7a0d, 0x7ae9,
0x7bc5, 0x7c9f, 0x7d78, 0x7e50, 0x7f26, 0x7ffc,
0x80d0, 0x81a3, 0x8274, 0x8345, 0x8414, 0x84e2,
0x85af, 0x867b, 0x8746, 0x880f, 0x88d8, 0x899f,
0x8a65, 0x8b2b, 0x8bef, 0x8cb2, 0x8d74, 0x8e35,
0x8ef4, 0x8fb3, 0x9071, 0x912e, 0x91ea, 0x92a4,
0x935e, 0x9417, 0x94cf, 0x9586, 0x963c, 0x96f0,
0x97a4, 0x9857, 0x990a, 0x99bb, 0x9a6b, 0x9b1a,
0x9bc9, 0x9c76, 0x9d23, 0x9dcf, 0x9e7a, 0x9f24,
0x9fcd, 0xa075, 0xa11c, 0xa1c3, 0xa269, 0xa30e,
0xa3b2, 0xa455, 0xa4f7, 0xa599, 0xa63a, 0xa6da,
0xa779, 0xa818, 0xa8b5, 0xa952, 0xa9ef, 0xaa8a,
0xab25, 0xabbe, 0xac58, 0xacf0, 0xad88, 0xae1f,
0xaeb5, 0xaf4a, 0xafdf, 0xb073, 0xb107, 0xb199,
0xb22b, 0xb2bd, 0xb34d, 0xb3dd, 0xb46c, 0xb4fb,
0xb589, 0xb616, 0xb6a3, 0xb72f, 0xb7ba, 0xb845,
0xb8cf, 0xb958, 0xb9e1, 0xba69, 0xbaf1, 0xbb78,
0xbbfe, 0xbc84, 0xbd09, 0xbd8d, 0xbe11
];
struct Sampler {
ticks_remain: u32,
ticks_now: u32,
ticks_unit: u32,
ticks_all: u32,
ticks_extra: u32,
ticks_extra_all: u32,
}
impl Sampler {
fn new(freq1: u32, freq2: u32) -> Self {
let unit = freq1 / freq2;
let extra = freq1 - unit * freq2;
Sampler {
ticks_remain: freq1 - extra,
ticks_now: 0,
ticks_unit: unit,
ticks_all: freq1 - extra,
ticks_extra: extra,
ticks_extra_all: extra
}
}
fn tick(&mut self) -> (bool, bool) {
let unit = self.ticks_unit;
if self.ticks_now == 0 {
self.ticks_now = unit;
self.ticks_remain -= unit;
if self.ticks_remain == 0 {
/* compensate to last exactly 1 sec */
self.ticks_now += self.ticks_remain;
/* reload for the next second */
self.ticks_remain = self.ticks_all;
self.ticks_extra = self.ticks_extra_all;
}
if self.ticks_extra > 0 {
self.ticks_extra -= 1;
self.ticks_now += 1;
}
}
self.ticks_now -= 1;
(self.ticks_now == 0, self.ticks_remain == self.ticks_all)
}
}
pub struct Pulse {
/* envelope */
env_period: u8,
env_lvl: u8,
decay_lvl: u8,
env_start: bool,
env_loop: bool,
env_const: bool,
env_vol: u8,
/* sweep */
swp_count: u8,
swp_period: u8,
swp_lvl: u8,
swp_en: bool,
swp_neg: bool,
swp_rld: bool,
muted: bool,
/* length counter */
len_lvl: u8,
/* timer */
timer_period: u16,
timer_lvl: u16,
/* sequencer */
seq_wave: u8,
seq_cnt: u8,
/* channel */
enabled: bool,
comple: bool,
}
impl Pulse {
fn tick_env(&mut self) {
/* should be clocked by frame counter */
if !self.env_start {
if self.env_lvl == 0 {
self.env_lvl = self.env_period;
if self.decay_lvl == 0 {
if self.env_loop {
self.decay_lvl = 15;
}
} else {
self.decay_lvl -= 1;
}
} else {
self.env_lvl -= 1;
}
} else {
self.decay_lvl = 15;
self.env_start = false;
self.env_lvl = self.env_period;
}
}
fn tick_sweep(&mut self) {
let mut reload = self.swp_rld;
if self.swp_lvl == 0 {
reload = true;
let p = self.timer_period;
let mut delta = p >> self.swp_count;
if self.swp_neg {
delta = !delta;
if self.comple { delta += 1; } /* two's complement */
}
p.wrapping_add(delta);
self.muted = self.timer_period < 8 || (self.timer_period >> 11 != 0);
if !self.muted && self.swp_en && self.swp_count != 0 {
self.timer_period = p;
}
} else {
self.swp_lvl -= 1;
}
if reload {
self.swp_lvl = self.swp_period;
self.swp_rld = false;
}
}
fn