Modified ym2612 to use 16 bit signed number a bit sooner

This commit is contained in:
transistor 2023-04-30 16:48:40 -07:00
parent 71cd47466b
commit 074d29c023

View File

@ -163,14 +163,15 @@ lazy_static! {
.map(|i| { .map(|i| {
let sine = (((i * 2 + 1) as f32 / SIN_TABLE_SIZE as f32) * f32::consts::PI / 2.0).sin(); let sine = (((i * 2 + 1) as f32 / SIN_TABLE_SIZE as f32) * f32::consts::PI / 2.0).sin();
let log_sine = -1.0 * sine.log2(); let log_sine = -1.0 * sine.log2();
// Convert to fixed decimal notation with 4.8 bit format
(log_sine * (1 << 8) as f32) as u16 (log_sine * (1 << 8) as f32) as u16
}) })
.collect(); .collect();
static ref POW_TABLE: Vec<u16> = (0..POW_TABLE_SIZE) static ref POW_TABLE: Vec<i16> = (0..POW_TABLE_SIZE)
.map(|i| { .map(|i| {
let linear = 2.0_f32.powf(-1.0 * (((i & 0xFF) + 1) as f32 / 256.0)); let linear = 2.0_f32.powf(-1.0 * (((i & 0xFF) + 1) as f32 / 256.0));
let linear_fixed = (linear * (1 << 11) as f32) as u16; let linear_fixed = (linear * (1 << 11) as f32) as i16;
let shift = (i as i32 >> 8) - 2; let shift = (i as i32 >> 8) - 2;
if shift < 0 { if shift < 0 {
linear_fixed << (0 - shift) linear_fixed << (0 - shift)
@ -226,8 +227,8 @@ impl EnvelopeGenerator {
sustain_level: 0, sustain_level: 0,
rates: [0; 4], rates: [0; 4],
envelope_state: EnvelopeState::Attack, envelope_state: EnvelopeState::Release,
envelope: 0, envelope: MAX_ENVELOPE,
last_envelope_clock: 0, last_envelope_clock: 0,
} }
} }
@ -410,8 +411,8 @@ impl PhaseGenerator {
self.increment = increment; self.increment = increment;
} }
fn update_phase(&mut self, _fm_clock: FmClock) -> u16 { fn update_phase(&mut self, _fm_clock: FmClock) -> i16 {
let phase = ((self.counter >> 10) & 0x3FF) as u16; let phase = ((self.counter >> 10) & 0x3FF) as i16;
self.counter += self.increment; self.counter += self.increment;
phase phase
} }
@ -455,7 +456,7 @@ struct Operator {
debug_name: String, debug_name: String,
phase: PhaseGenerator, phase: PhaseGenerator,
envelope: EnvelopeGenerator, envelope: EnvelopeGenerator,
output: u16, output: i16,
} }
impl Operator { impl Operator {
@ -497,18 +498,29 @@ impl Operator {
self.phase.reset(); self.phase.reset();
} }
fn get_output(&mut self, modulator: u16, clocks: (FmClock, EnvelopeClock)) -> u16 { fn get_output(&mut self, modulator: i16, clocks: (FmClock, EnvelopeClock)) -> i16 {
let (fm_clock, envelope_clock) = clocks; let (fm_clock, envelope_clock) = clocks;
let envelope = self.envelope.get_envelope(envelope_clock, self.phase.get_rate_adjust()); let envelope = self.envelope.get_envelope(envelope_clock, self.phase.get_rate_adjust());
let phase = self.phase.update_phase(fm_clock); let phase = self.phase.update_phase(fm_clock);
let mod_phase = phase + modulator; let mod_phase = phase + modulator;
let mut output = POW_TABLE[(SIN_TABLE[(mod_phase & 0x1FF) as usize] + envelope) as usize]; // The sine table contains the first half of the wave as an attenuation value
// Use the phase with the sign truncated to get the attenuation, plus the
// attenuation from the envelope, to get the total attenuation at this point
let attenuation = SIN_TABLE[(mod_phase & 0x1FF) as usize] + envelope;
// The power table contains the 13-bit output (not including the sign) for a
// 12 bit attenuation value, which is then negated based on the sign of the phase
let mut output = POW_TABLE[attenuation as usize];
// If the original phase was in the negative portion, invert the output
// since the sine wave's second half is a mirror of the first half
if mod_phase & 0x200 != 0 { if mod_phase & 0x200 != 0 {
output = (output as i16 * -1) as u16 output = output * -1;
} }
// The output is now represented with a 16-bit signed number in the range of -0x1FFF and 0x1FFF
// Save the output for use as feedback later // Save the output for use as feedback later
self.output = output; self.output = output;
@ -530,7 +542,7 @@ struct Channel {
key_state: u8, key_state: u8,
next_key_clock: FmClock, next_key_clock: FmClock,
next_key_state: u8, next_key_state: u8,
op1_output: [u16; 2], op1_output: [i16; 2],
} }
impl Channel { impl Channel {
@ -580,25 +592,24 @@ impl Channel {
} else { } else {
0 0
}; };
let output = self.get_algorithm_output(clocks, feedback);
let output = if output & 0x2000 == 0 { let output = self.get_algorithm_output(clocks, feedback);
output as i16
} else {
(output | 0xC000) as i16
};
self.op1_output[0] = self.op1_output[1]; self.op1_output[0] = self.op1_output[1];
self.op1_output[1] = self.operators[0].output; self.op1_output[1] = self.operators[0].output;
let sample = output as f32 / (1 << 14) as f32; //let output = sign_extend_u16(output, 14);
//let output = output * 2 / 3;
let sample = output as f32 / (1 << 13) as f32;
let left = if self.enabled.0 { sample } else { 0.0 }; let left = if self.enabled.0 { sample } else { 0.0 };
let right = if self.enabled.1 { sample } else { 0.0 }; let right = if self.enabled.1 { sample } else { 0.0 };
(left, right) (left, right)
} }
fn get_algorithm_output(&mut self, clocks: (FmClock, EnvelopeClock), feedback: u16) -> u16 { fn get_algorithm_output(&mut self, clocks: (FmClock, EnvelopeClock), feedback: i16) -> i16 {
match self.algorithm { match self.algorithm {
OperatorAlgorithm::A0 => { OperatorAlgorithm::A0 => {
let modulator0 = self.operators[0].get_output(feedback, clocks); let modulator0 = self.operators[0].get_output(feedback, clocks);
@ -650,6 +661,14 @@ impl Channel {
} }
} }
fn sign_extend_u16(value: u16, size: usize) -> i16 {
if value & (1 << (size + 1)) == 0 {
value as i16
} else {
(value | 0xFFFF << (size + 1)) as i16
}
}
struct Dac { struct Dac {
enabled: bool, enabled: bool,