mirror of
https://github.com/transistorfet/moa.git
synced 2024-11-28 20:50:13 +00:00
Additional ym2612 improvements
This commit is contained in:
parent
31faf70d97
commit
dcc3c97dd6
@ -281,3 +281,31 @@ impl Frequency {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Mul<u32> for Frequency {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn mul(self, rhs: u32) -> Self::Output {
|
||||||
|
Self::from_hz(self.hertz * rhs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MulAssign<u32> for Frequency {
|
||||||
|
fn mul_assign(&mut self, rhs: u32) {
|
||||||
|
*self = Self::from_hz(self.hertz * rhs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Div<u32> for Frequency {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn div(self, rhs: u32) -> Self::Output {
|
||||||
|
Self::from_hz(self.hertz / rhs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DivAssign<u32> for Frequency {
|
||||||
|
fn div_assign(&mut self, rhs: u32) {
|
||||||
|
*self = Self::from_hz(self.hertz / rhs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -120,6 +120,7 @@ const OPERATORS: usize = 4;
|
|||||||
const MAX_ENVELOPE: u16 = 0x3FC;
|
const MAX_ENVELOPE: u16 = 0x3FC;
|
||||||
|
|
||||||
|
|
||||||
|
type FmClock = u64;
|
||||||
type EnvelopeClock = u64;
|
type EnvelopeClock = u64;
|
||||||
|
|
||||||
#[repr(usize)]
|
#[repr(usize)]
|
||||||
@ -173,8 +174,12 @@ impl EnvelopeGenerator {
|
|||||||
fn notify_key_change(&mut self, state: bool, envelope_clock: EnvelopeClock) {
|
fn notify_key_change(&mut self, state: bool, envelope_clock: EnvelopeClock) {
|
||||||
if state {
|
if state {
|
||||||
self.next_envelope_clock = envelope_clock;
|
self.next_envelope_clock = envelope_clock;
|
||||||
self.envelope_state = EnvelopeState::Attack;
|
|
||||||
self.envelope = 0;
|
self.envelope = 0;
|
||||||
|
if self.rates[EnvelopeState::Attack as usize] < 62 {
|
||||||
|
self.envelope_state = EnvelopeState::Attack;
|
||||||
|
} else {
|
||||||
|
self.envelope_state = EnvelopeState::Decay;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
self.envelope_state = EnvelopeState::Release;
|
self.envelope_state = EnvelopeState::Release;
|
||||||
}
|
}
|
||||||
@ -200,7 +205,6 @@ impl EnvelopeGenerator {
|
|||||||
|
|
||||||
match self.envelope_state {
|
match self.envelope_state {
|
||||||
EnvelopeState::Attack => {
|
EnvelopeState::Attack => {
|
||||||
//let new_envelope = self.envelope + increment * (((1024 - self.envelope) / 16) + 1);
|
|
||||||
let new_envelope = ((!self.envelope * increment) >> 4) & 0xFFFC;
|
let new_envelope = ((!self.envelope * increment) >> 4) & 0xFFFC;
|
||||||
if new_envelope > self.envelope {
|
if new_envelope > self.envelope {
|
||||||
self.envelope_state = EnvelopeState::Decay;
|
self.envelope_state = EnvelopeState::Decay;
|
||||||
@ -216,9 +220,10 @@ impl EnvelopeGenerator {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.debug_name == "ch 3, op 2" {
|
// TODO remove this
|
||||||
println!("{}: {:?} {} {}", update_cycle, self.envelope_state, self.envelope, self.sustain_level);
|
//if self.debug_name == "ch 3, op 2" {
|
||||||
}
|
// println!("{}: {:?} {} {}", update_cycle, self.envelope_state, self.envelope, self.sustain_level);
|
||||||
|
//}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -308,7 +313,7 @@ struct Channel {
|
|||||||
debug_name: String,
|
debug_name: String,
|
||||||
operators: Vec<Operator>,
|
operators: Vec<Operator>,
|
||||||
key_state: u8,
|
key_state: u8,
|
||||||
next_key_clock: ClockTime,
|
next_key_clock: FmClock,
|
||||||
next_key_state: u8,
|
next_key_state: u8,
|
||||||
base_frequency: f32,
|
base_frequency: f32,
|
||||||
algorithm: OperatorAlgorithm,
|
algorithm: OperatorAlgorithm,
|
||||||
@ -320,7 +325,7 @@ impl Channel {
|
|||||||
debug_name: debug_name.clone(),
|
debug_name: debug_name.clone(),
|
||||||
operators: (0..OPERATORS).map(|i| Operator::new(format!("{}, op {}", debug_name, i), sample_rate)).collect(),
|
operators: (0..OPERATORS).map(|i| Operator::new(format!("{}, op {}", debug_name, i), sample_rate)).collect(),
|
||||||
key_state: 0,
|
key_state: 0,
|
||||||
next_key_clock: ClockTime::START,
|
next_key_clock: 0,
|
||||||
next_key_state: 0,
|
next_key_state: 0,
|
||||||
base_frequency: 0.0,
|
base_frequency: 0.0,
|
||||||
algorithm: OperatorAlgorithm::A0,
|
algorithm: OperatorAlgorithm::A0,
|
||||||
@ -334,13 +339,13 @@ impl Channel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change_key_state(&mut self, clock: ClockTime, key: u8) {
|
fn change_key_state(&mut self, fm_clock: FmClock, key: u8) {
|
||||||
self.next_key_clock = clock;
|
self.next_key_clock = fm_clock;
|
||||||
self.next_key_state = key;
|
self.next_key_state = key;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_key_change(&mut self, clock: ClockTime, envelope_clock: EnvelopeClock) {
|
fn check_key_change(&mut self, fm_clock: FmClock, envelope_clock: EnvelopeClock) {
|
||||||
if self.key_state != self.next_key_state && clock >= self.next_key_clock {
|
if self.key_state != self.next_key_state && fm_clock >= self.next_key_clock {
|
||||||
self.key_state = self.next_key_state;
|
self.key_state = self.next_key_state;
|
||||||
for (i, operator) in self.operators.iter_mut().enumerate() {
|
for (i, operator) in self.operators.iter_mut().enumerate() {
|
||||||
operator.notify_key_change(((self.key_state >> i) & 0x01) != 0, envelope_clock);
|
operator.notify_key_change(((self.key_state >> i) & 0x01) != 0, envelope_clock);
|
||||||
@ -349,8 +354,8 @@ impl Channel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_sample(&mut self, clock: ClockTime, envelope_clock: EnvelopeClock) -> f32 {
|
fn get_sample(&mut self, fm_clock: FmClock, envelope_clock: EnvelopeClock) -> f32 {
|
||||||
self.check_key_change(clock, envelope_clock);
|
self.check_key_change(fm_clock, envelope_clock);
|
||||||
|
|
||||||
if self.key_state != 0 {
|
if self.key_state != 0 {
|
||||||
self.get_algorithm_sample(envelope_clock)
|
self.get_algorithm_sample(envelope_clock)
|
||||||
@ -446,6 +451,7 @@ pub struct Ym2612 {
|
|||||||
selected_reg_1: Option<NonZeroU8>,
|
selected_reg_1: Option<NonZeroU8>,
|
||||||
|
|
||||||
clock_frequency: Frequency,
|
clock_frequency: Frequency,
|
||||||
|
fm_clock_period: ClockDuration,
|
||||||
envelope_clock_period: ClockDuration,
|
envelope_clock_period: ClockDuration,
|
||||||
channels: Vec<Channel>,
|
channels: Vec<Channel>,
|
||||||
channel_frequencies: [(u8, u16); CHANNELS],
|
channel_frequencies: [(u8, u16); CHANNELS],
|
||||||
@ -468,13 +474,18 @@ impl Ym2612 {
|
|||||||
pub fn create<H: Host>(host: &mut H, clock_frequency: Frequency) -> Result<Self, Error> {
|
pub fn create<H: Host>(host: &mut H, clock_frequency: Frequency) -> Result<Self, Error> {
|
||||||
let source = host.create_audio_source()?;
|
let source = host.create_audio_source()?;
|
||||||
let sample_rate = source.samples_per_second();
|
let sample_rate = source.samples_per_second();
|
||||||
|
let fm_clock = clock_frequency / 6 / 24;
|
||||||
|
let fm_clock_period = fm_clock.period_duration();
|
||||||
|
let envelope_clock_period = (fm_clock / 3).period_duration();
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
source,
|
source,
|
||||||
selected_reg_0: None,
|
selected_reg_0: None,
|
||||||
selected_reg_1: None,
|
selected_reg_1: None,
|
||||||
|
|
||||||
clock_frequency,
|
clock_frequency,
|
||||||
envelope_clock_period: clock_frequency.period_duration() * 144 * 3, // Nemesis shows * 351? Not sure why the difference
|
fm_clock_period,
|
||||||
|
envelope_clock_period,
|
||||||
channels: (0..CHANNELS).map(|i| Channel::new(format!("ch {}", i), sample_rate)).collect(),
|
channels: (0..CHANNELS).map(|i| Channel::new(format!("ch {}", i), sample_rate)).collect(),
|
||||||
channel_frequencies: [(0, 0); CHANNELS],
|
channel_frequencies: [(0, 0); CHANNELS],
|
||||||
|
|
||||||
@ -506,17 +517,18 @@ impl Steppable for Ym2612 {
|
|||||||
let mut buffer = vec![0.0; samples];
|
let mut buffer = vec![0.0; samples];
|
||||||
for (i, buffered_sample) in buffer.iter_mut().enumerate().take(samples) {
|
for (i, buffered_sample) in buffer.iter_mut().enumerate().take(samples) {
|
||||||
let sample_clock = system.clock + (sample_duration * i as u64);
|
let sample_clock = system.clock + (sample_duration * i as u64);
|
||||||
|
let fm_clock = sample_clock.as_duration() / self.fm_clock_period;
|
||||||
let envelope_clock = sample_clock.as_duration() / self.envelope_clock_period;
|
let envelope_clock = sample_clock.as_duration() / self.envelope_clock_period;
|
||||||
let mut sample = 0.0;
|
let mut sample = 0.0;
|
||||||
|
|
||||||
for ch in 0..(CHANNELS - 1) {
|
for ch in 0..(CHANNELS - 1) {
|
||||||
sample += self.channels[ch].get_sample(sample_clock, envelope_clock);
|
sample += self.channels[ch].get_sample(fm_clock, envelope_clock);
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.dac.enabled {
|
if self.dac.enabled {
|
||||||
sample += self.dac.get_sample();
|
sample += self.dac.get_sample();
|
||||||
} else {
|
} else {
|
||||||
sample += self.channels[CHANNELS - 1].get_sample(sample_clock, envelope_clock);
|
sample += self.channels[CHANNELS - 1].get_sample(fm_clock, envelope_clock);
|
||||||
}
|
}
|
||||||
|
|
||||||
*buffered_sample = sample.clamp(-1.0, 1.0);
|
*buffered_sample = sample.clamp(-1.0, 1.0);
|
||||||
@ -559,7 +571,7 @@ impl Ym2612 {
|
|||||||
return;
|
return;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
self.channels[ch].change_key_state(clock, data >> 4);
|
self.channels[ch].change_key_state(clock.as_duration() / self.fm_clock_period, data >> 4);
|
||||||
},
|
},
|
||||||
|
|
||||||
0x2a => {
|
0x2a => {
|
||||||
|
Loading…
Reference in New Issue
Block a user