2021-01-19 04:54:38 +00:00
|
|
|
use crate::instruction::Cycles;
|
|
|
|
|
2021-01-03 08:05:46 +00:00
|
|
|
#[derive(Debug, Clone, Copy, Default)]
|
|
|
|
pub struct Sound {
|
2021-01-18 00:58:57 +00:00
|
|
|
pub control: SoundControl,
|
2021-01-17 23:33:12 +00:00
|
|
|
pub ch1: Channel1,
|
2021-01-18 00:58:57 +00:00
|
|
|
}
|
|
|
|
|
2021-01-19 04:54:38 +00:00
|
|
|
impl Sound {
|
|
|
|
pub fn step(&mut self, _cycles: Cycles) {
|
|
|
|
//
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-18 00:58:57 +00:00
|
|
|
#[derive(Debug, Clone, Copy, Default)]
|
|
|
|
pub struct SoundControl {
|
|
|
|
pub channel: ChannelControl,
|
2021-01-17 23:33:12 +00:00
|
|
|
pub select: SoundOutputSelect,
|
2021-01-18 00:58:57 +00:00
|
|
|
pub status: SoundStatus,
|
2021-01-03 08:05:46 +00:00
|
|
|
}
|
|
|
|
|
2021-01-19 06:30:10 +00:00
|
|
|
#[derive(Debug, Clone, Copy, Default)]
|
|
|
|
pub struct Frequency {
|
|
|
|
initial: bool,
|
|
|
|
freq_type: FrequencyType,
|
|
|
|
lo: u8, // Bottom 8 bits
|
|
|
|
hi: u8, // Top 3 bits (11 bits total)
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Copy)]
|
|
|
|
enum FrequencyType {
|
2021-01-19 07:36:44 +00:00
|
|
|
Counter = 0,
|
2021-03-16 00:19:40 +00:00
|
|
|
Consecutive = 1,
|
2021-01-19 06:30:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl From<u8> for FrequencyType {
|
|
|
|
fn from(byte: u8) -> Self {
|
|
|
|
match byte {
|
|
|
|
0b00 => Self::Counter,
|
2021-03-16 00:19:40 +00:00
|
|
|
0b01 => Self::Consecutive,
|
|
|
|
_ => unreachable!("{} is not a valid number for FrequencyType"),
|
2021-01-19 06:30:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for FrequencyType {
|
|
|
|
fn default() -> Self {
|
|
|
|
Self::Counter
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Frequency {
|
|
|
|
fn get_11bit_freq(&self) -> u16 {
|
|
|
|
(self.hi as u16) << 8 | self.lo as u16
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn set_lo(&mut self, byte: u8) {
|
|
|
|
self.lo = byte;
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_lo(&self) -> u8 {
|
|
|
|
self.lo
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn set_hi(&mut self, byte: u8) {
|
|
|
|
*self = Self {
|
|
|
|
initial: byte >> 7 == 0x01,
|
|
|
|
freq_type: ((byte >> 6) & 0x01).into(),
|
|
|
|
lo: self.lo,
|
|
|
|
hi: byte & 0x07,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_hi(&self) -> u8 {
|
|
|
|
(self.initial as u8) << 7 | (self.freq_type as u8) << 6 | self.hi
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-03 08:05:46 +00:00
|
|
|
#[derive(Debug, Clone, Copy, Default)]
|
|
|
|
pub struct SoundStatus {
|
|
|
|
pub all_enabled: bool, // You can actually write to this one.
|
|
|
|
sound_4: bool,
|
|
|
|
sound_3: bool,
|
|
|
|
sound_2: bool,
|
|
|
|
sound_1: bool,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<u8> for SoundStatus {
|
|
|
|
fn from(byte: u8) -> Self {
|
|
|
|
Self {
|
|
|
|
all_enabled: (byte >> 7) & 0x01 == 0x01,
|
|
|
|
sound_4: (byte >> 3) & 0x01 == 0x01,
|
|
|
|
sound_3: (byte >> 2) & 0x01 == 0x01,
|
|
|
|
sound_2: (byte >> 1) & 0x01 == 0x01,
|
|
|
|
sound_1: (byte >> 0) & 0x01 == 0x01,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<SoundStatus> for u8 {
|
|
|
|
fn from(status: SoundStatus) -> Self {
|
|
|
|
(status.all_enabled as u8) << 7
|
|
|
|
| (status.sound_4 as u8) << 3
|
|
|
|
| (status.sound_3 as u8) << 2
|
|
|
|
| (status.sound_2 as u8) << 1
|
|
|
|
| (status.sound_1 as u8) << 0
|
|
|
|
}
|
|
|
|
}
|
2021-01-17 23:33:12 +00:00
|
|
|
|
|
|
|
#[derive(Debug, Clone, Copy, Default)]
|
|
|
|
pub struct Channel1 {
|
|
|
|
pub sound_duty: SoundDuty,
|
|
|
|
pub vol_envelope: VolumeEnvelope,
|
2021-01-19 06:30:10 +00:00
|
|
|
pub freq: Frequency,
|
2021-01-17 23:33:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Copy, Default)]
|
|
|
|
pub struct VolumeEnvelope {
|
|
|
|
init_vol: u8,
|
|
|
|
direction: EnvelopeDirection,
|
|
|
|
sweep_count: u8,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<u8> for VolumeEnvelope {
|
|
|
|
fn from(byte: u8) -> Self {
|
|
|
|
Self {
|
|
|
|
init_vol: byte >> 4, // Bit 7 -> 4
|
|
|
|
direction: ((byte >> 3) & 0x01).into(), // Bit 3
|
|
|
|
sweep_count: byte & 0x07, // Bits 2 -> 0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<VolumeEnvelope> for u8 {
|
|
|
|
fn from(envelope: VolumeEnvelope) -> Self {
|
2021-01-19 07:36:44 +00:00
|
|
|
let dir_bit: u8 = envelope.direction as u8;
|
2021-01-17 23:33:12 +00:00
|
|
|
let mut byte = envelope.init_vol << 4;
|
|
|
|
byte |= dir_bit << 3;
|
|
|
|
byte |= envelope.sweep_count;
|
|
|
|
byte
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Copy)]
|
|
|
|
enum EnvelopeDirection {
|
2021-01-19 07:36:44 +00:00
|
|
|
Decrease = 0,
|
|
|
|
Increase = 1,
|
2021-01-17 23:33:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl From<u8> for EnvelopeDirection {
|
|
|
|
fn from(byte: u8) -> Self {
|
|
|
|
match byte {
|
|
|
|
0b00 => Self::Decrease,
|
|
|
|
0b01 => Self::Increase,
|
2021-01-19 07:36:44 +00:00
|
|
|
_ => unreachable!(
|
|
|
|
"{:#04X} is not a possible value for EnvelopeDirection",
|
|
|
|
byte
|
|
|
|
),
|
2021-01-17 23:33:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for EnvelopeDirection {
|
|
|
|
fn default() -> Self {
|
2021-01-19 07:36:44 +00:00
|
|
|
Self::Decrease
|
2021-01-17 23:33:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Copy, Default)]
|
|
|
|
pub struct SoundDuty {
|
|
|
|
wave_pattern: WaveDuty,
|
|
|
|
sound_length: u8, //
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<u8> for SoundDuty {
|
|
|
|
fn from(byte: u8) -> Self {
|
|
|
|
let pattern = byte >> 6; // Get bytes 7 and 6
|
|
|
|
let sound_length = byte & 0x3F; // Clear bytes 7 and 6
|
|
|
|
|
|
|
|
SoundDuty {
|
|
|
|
wave_pattern: pattern.into(),
|
|
|
|
sound_length,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<SoundDuty> for u8 {
|
|
|
|
fn from(duty: SoundDuty) -> Self {
|
2021-01-19 07:36:44 +00:00
|
|
|
let mut byte: u8 = duty.wave_pattern as u8;
|
2021-01-17 23:33:12 +00:00
|
|
|
byte = (byte << 6) | duty.sound_length;
|
|
|
|
byte
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Copy)]
|
|
|
|
pub enum WaveDuty {
|
2021-01-19 07:36:44 +00:00
|
|
|
OneEighth = 0, // 12.5% ( _-------_-------_------- )
|
|
|
|
OneQuarter = 1, // 25% ( __------__------__------ )
|
|
|
|
OneHalf = 2, // 50% ( ____----____----____---- ) (normal)
|
|
|
|
ThreeQuarters = 3, // 75% ( ______--______--______-- )
|
2021-01-17 23:33:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for WaveDuty {
|
|
|
|
fn default() -> Self {
|
|
|
|
Self::OneEighth // Rationale: OneEighth is 0x00
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<u8> for WaveDuty {
|
|
|
|
fn from(byte: u8) -> Self {
|
|
|
|
match byte {
|
|
|
|
0b00 => Self::OneEighth,
|
|
|
|
0b01 => Self::OneQuarter,
|
|
|
|
0b10 => Self::OneHalf,
|
|
|
|
0b11 => Self::ThreeQuarters,
|
|
|
|
_ => unreachable!("{:#04X} is not a valid value for a Sound Wave", byte),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Copy, Default)]
|
|
|
|
pub struct SoundOutputSelect {
|
|
|
|
pub snd4_term2: bool,
|
|
|
|
pub snd3_term2: bool,
|
|
|
|
pub snd2_term2: bool,
|
|
|
|
pub snd1_term2: bool,
|
|
|
|
pub snd4_term1: bool,
|
|
|
|
pub snd3_term1: bool,
|
|
|
|
pub snd2_term1: bool,
|
|
|
|
pub snd1_term1: bool,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<SoundOutputSelect> for u8 {
|
|
|
|
fn from(select: SoundOutputSelect) -> Self {
|
|
|
|
(select.snd4_term2 as u8) << 7
|
|
|
|
| (select.snd3_term2 as u8) << 6
|
|
|
|
| (select.snd2_term2 as u8) << 5
|
|
|
|
| (select.snd1_term2 as u8) << 4
|
|
|
|
| (select.snd4_term1 as u8) << 3
|
|
|
|
| (select.snd3_term1 as u8) << 2
|
|
|
|
| (select.snd2_term1 as u8) << 1
|
|
|
|
| (select.snd1_term1 as u8)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<u8> for SoundOutputSelect {
|
|
|
|
fn from(byte: u8) -> Self {
|
|
|
|
Self {
|
|
|
|
snd4_term2: byte >> 7 == 0x01,
|
|
|
|
snd3_term2: (byte >> 6) & 0x01 == 0x01,
|
|
|
|
snd2_term2: (byte >> 5) & 0x01 == 0x01,
|
|
|
|
snd1_term2: (byte >> 4) & 0x01 == 0x01,
|
|
|
|
snd4_term1: (byte >> 3) & 0x01 == 0x01,
|
|
|
|
snd3_term1: (byte >> 2) & 0x01 == 0x01,
|
|
|
|
snd2_term1: (byte >> 1) & 0x01 == 0x01,
|
|
|
|
snd1_term1: byte & 0x01 == 0x01,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-01-18 00:58:57 +00:00
|
|
|
|
|
|
|
#[derive(Debug, Clone, Copy, Default)]
|
|
|
|
pub struct ChannelControl {
|
|
|
|
vin_to_term2: bool,
|
|
|
|
term2_level: u8,
|
|
|
|
vin_to_term1: bool,
|
|
|
|
term1_level: u8,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<u8> for ChannelControl {
|
|
|
|
fn from(byte: u8) -> Self {
|
|
|
|
Self {
|
|
|
|
vin_to_term2: byte >> 7 == 0x01, // Get 7th bit
|
|
|
|
term2_level: (byte & 0x7F) >> 4, // Clear 7th then get 6 -> 4th bit
|
|
|
|
vin_to_term1: (byte >> 3) & 0x01 == 0x01,
|
|
|
|
term1_level: byte & 0x07, // Bits 2 -> 0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<ChannelControl> for u8 {
|
|
|
|
fn from(control: ChannelControl) -> Self {
|
|
|
|
(control.vin_to_term1 as u8) << 7
|
|
|
|
| (control.term2_level as u8) << 4
|
|
|
|
| (control.vin_to_term1 as u8) << 3
|
|
|
|
| control.term1_level as u8
|
|
|
|
}
|
|
|
|
}
|