feat(apu): add ChannelOutputs struct and channel_outputs() method
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
use super::types::{Apu, ApuStateTail};
|
||||
use super::types::{Apu, ApuStateTail, ChannelOutputs};
|
||||
|
||||
impl Apu {
|
||||
pub fn new() -> Self {
|
||||
@@ -287,4 +287,74 @@ impl Apu {
|
||||
self.noise_timer_counter = state.noise_timer_counter;
|
||||
self.noise_lfsr = if state.noise_lfsr == 0 { 1 } else { state.noise_lfsr };
|
||||
}
|
||||
|
||||
pub fn channel_outputs(&self) -> ChannelOutputs {
|
||||
const PULSE_DUTY_TABLE: [[u8; 8]; 4] = [
|
||||
[0, 1, 0, 0, 0, 0, 0, 0],
|
||||
[0, 1, 1, 0, 0, 0, 0, 0],
|
||||
[0, 1, 1, 1, 1, 0, 0, 0],
|
||||
[1, 0, 0, 1, 1, 1, 1, 1],
|
||||
];
|
||||
const TRIANGLE_SEQUENCE: [u8; 32] = [
|
||||
15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0,
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
];
|
||||
|
||||
let pulse1 = {
|
||||
let duty = (self.io[0x00] >> 6) as usize;
|
||||
let step = self.pulse_duty_step[0] as usize;
|
||||
let volume = if (self.io[0x00] & 0x10) != 0 {
|
||||
self.io[0x00] & 0x0F
|
||||
} else {
|
||||
self.envelope_decay[0]
|
||||
};
|
||||
let active = (self.channel_enable_mask & 0x01) != 0
|
||||
&& self.length_counters[0] > 0
|
||||
&& PULSE_DUTY_TABLE[duty][step] != 0
|
||||
&& !self.sweep_mutes_channel(0, 0x02);
|
||||
if active { volume } else { 0 }
|
||||
};
|
||||
|
||||
let pulse2 = {
|
||||
let duty = (self.io[0x04] >> 6) as usize;
|
||||
let step = self.pulse_duty_step[1] as usize;
|
||||
let volume = if (self.io[0x04] & 0x10) != 0 {
|
||||
self.io[0x04] & 0x0F
|
||||
} else {
|
||||
self.envelope_decay[1]
|
||||
};
|
||||
let active = (self.channel_enable_mask & 0x02) != 0
|
||||
&& self.length_counters[1] > 0
|
||||
&& PULSE_DUTY_TABLE[duty][step] != 0
|
||||
&& !self.sweep_mutes_channel(1, 0x06);
|
||||
if active { volume } else { 0 }
|
||||
};
|
||||
|
||||
let triangle = {
|
||||
let active = (self.channel_enable_mask & 0x04) != 0
|
||||
&& self.length_counters[2] > 0
|
||||
&& self.triangle_linear_counter > 0;
|
||||
if active {
|
||||
TRIANGLE_SEQUENCE[self.triangle_step as usize & 0x1F]
|
||||
} else {
|
||||
0
|
||||
}
|
||||
};
|
||||
|
||||
let noise = {
|
||||
let volume = if (self.io[0x0C] & 0x10) != 0 {
|
||||
self.io[0x0C] & 0x0F
|
||||
} else {
|
||||
self.envelope_decay[2]
|
||||
};
|
||||
let active = (self.channel_enable_mask & 0x08) != 0
|
||||
&& self.length_counters[3] > 0
|
||||
&& (self.noise_lfsr & 1) == 0;
|
||||
if active { volume } else { 0 }
|
||||
};
|
||||
|
||||
let dmc = self.dmc_output_level;
|
||||
|
||||
ChannelOutputs { pulse1, pulse2, triangle, noise, dmc }
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user