Correct-er implemenation of psg3/psg4 relationship in deflemask

master
Ashley N. 2023-08-28 21:22:17 -04:00
parent f276051133
commit 21b3de950e
2 changed files with 37 additions and 15 deletions

View File

@ -309,9 +309,10 @@ pub fn get_events_for_channel( channels: &mut [Channel], active_channel: usize,
// Key on or key off note // Key on or key off note
if let Some( note ) = &row.note { if let Some( note ) = &row.note {
if let Note::NoteOff = note { if let Note::NoteOff = note {
channels[ active_channel ].active_note = None; channels[ active_channel ].note_keyed = false;
events.push( vec![ ESF_NOTE_OFF | channels[ active_channel ].id ] ); events.push( vec![ ESF_NOTE_OFF | channels[ active_channel ].id ] );
} else { } else {
channels[ active_channel ].note_keyed = true;
channels[ active_channel ].active_note = Some( channels[ active_channel ].active_note = Some(
OctaveFrequency { OctaveFrequency {
octave: note.get_octave()?, octave: note.get_octave()?,
@ -334,16 +335,24 @@ pub fn get_events_for_channel( channels: &mut [Channel], active_channel: usize,
if let Effect::DcsgNoiseMode { mode, noise_type: _ } = dcsg_noise_mode { if let Effect::DcsgNoiseMode { mode, noise_type: _ } = dcsg_noise_mode {
if mode == &DcsgChannelMode::Ch3Frequency { if mode == &DcsgChannelMode::Ch3Frequency {
let index = channels.iter().position( | channel | channel.id == ESF_PSG_3 ).ok_or( "internal error: where is psg3??" )?; let index = channels.iter().position( | channel | channel.id == ESF_PSG_3 ).ok_or( "internal error: where is psg3??" )?;
// Copy over the active note to psg3 // Issue a set frequency for psg3 but don't tell the channel state (matches behaviour in deflemask)
channels[ index ].active_note = channels[ active_channel ].active_note; events.push( vec![
ESF_SET_FREQUENCY | channels[ index ].id,
( 0x000F & channels[ active_channel ].active_note.ok_or( "internal error: wtf happened here (1)??" )?.frequency ) as u8,
( ( 0x3F0 & channels[ active_channel ].active_note.ok_or( "internal error: wtf happened here (2)??" )?.frequency ) >> 4 ) as u8
] );
} }
} else { } else {
return Err( "internal error: wtf happened here (3)??" )? return Err( "internal error: wtf happened here (3)??" )?
} }
} else { } else {
let index = channels.iter().position( | channel | channel.id == ESF_PSG_3 ).ok_or( "internal error: where is psg3??" )?; let index = channels.iter().position( | channel | channel.id == ESF_PSG_3 ).ok_or( "internal error: where is psg3??" )?;
// Copy over the active note to psg3 // Issue a set frequency for psg3 but don't tell the channel state (matches behaviour in deflemask)
channels[ index ].active_note = channels[ active_channel ].active_note; events.push( vec![
ESF_SET_FREQUENCY | channels[ index ].id,
( 0x000F & channels[ active_channel ].active_note.ok_or( "internal error: wtf happened here (1)??" )?.frequency ) as u8,
( ( 0x3F0 & channels[ active_channel ].active_note.ok_or( "internal error: wtf happened here (2)??" )?.frequency ) >> 4 ) as u8
] );
} }
if let Some( noise_generator_setting ) = get_noise_generator_setting( note, dcsg_noise_mode )? { if let Some( noise_generator_setting ) = get_noise_generator_setting( note, dcsg_noise_mode )? {
@ -554,6 +563,18 @@ pub fn compact_delays( events: Vec<EchoEvent> ) -> Result<Vec<EchoEvent>, Box<dy
* for the next event. * for the next event.
*/ */
pub fn get_portamento( channel: &mut Channel, portamento_effect: &Effect ) -> Result<EchoEvent, Box<dyn Error>> { pub fn get_portamento( channel: &mut Channel, portamento_effect: &Effect ) -> Result<EchoEvent, Box<dyn Error>> {
if channel.id != ESF_FM_6_PCM && channel.id != ESF_PSG_4 {
// A portamento was called for on this channel, and if none was provided, we need to start with C, octave 0
// This replicates the behaviour in deflemask
if let None = channel.active_note {
channel.active_note = match channel.id {
ESF_FM_1..=ESF_FM_3 | ESF_FM_4..=ESF_FM_6 => Some( OctaveFrequency { octave: 0, frequency: get_fm_semitone_frequency( ESF_SEMITONE_C )? } ),
ESF_PSG_1..=ESF_PSG_3 => Some( OctaveFrequency { octave: 0, frequency: get_psg_semitone_frequency( 0, ESF_SEMITONE_C )? } ),
invalid_channel => return Err( format!( "internal error: get_note: invalid default portamento setting channel {:#04X}", invalid_channel ) )?
}
}
}
Ok( Ok(
if channel.id == ESF_FM_6_PCM || channel.id == ESF_PSG_4 { if channel.id == ESF_FM_6_PCM || channel.id == ESF_PSG_4 {
// Generate no events if channel is set to pcm // Generate no events if channel is set to pcm
@ -639,8 +660,8 @@ pub fn get_note_cut( channel: &mut Channel, note_cut_effect: &Effect, tick: u8 )
}; };
if tick >= after_ticks { if tick >= after_ticks {
if channel.active_note.is_some() { channel.note_keyed = false;
channel.active_note = None;
// Consume the note cut after we are done with it - it does not remain active // Consume the note cut after we are done with it - it does not remain active
channel.active_effects = channel.active_effects channel.active_effects = channel.active_effects
.clone() .clone()
@ -649,7 +670,6 @@ pub fn get_note_cut( channel: &mut Channel, note_cut_effect: &Effect, tick: u8 )
.collect(); .collect();
return Ok( vec![ ESF_NOTE_OFF | channel.id ] ); return Ok( vec![ ESF_NOTE_OFF | channel.id ] );
} }
}
// Nothing to generate this tick // Nothing to generate this tick
Ok( vec![] ) Ok( vec![] )

View File

@ -98,6 +98,7 @@ pub struct Channel {
pub id: u8, pub id: u8,
pub active_instrument: Option<u16>, pub active_instrument: Option<u16>,
pub active_note: Option<OctaveFrequency>, pub active_note: Option<OctaveFrequency>,
pub note_keyed: bool,
pub current_volume: Option<u8>, pub current_volume: Option<u8>,
pub active_effects: LinkedHashSet<Effect> pub active_effects: LinkedHashSet<Effect>
} }
@ -144,6 +145,7 @@ impl Channel {
id, id,
active_instrument: None, active_instrument: None,
active_note: None, active_note: None,
note_keyed: false,
current_volume: None, current_volume: None,
active_effects: LinkedHashSet::new() active_effects: LinkedHashSet::new()
} }