diff --git a/src/reskit/soundtrack/engines/echo/engine.rs b/src/reskit/soundtrack/engines/echo/engine.rs index 4ba5ac9..cc50e87 100644 --- a/src/reskit/soundtrack/engines/echo/engine.rs +++ b/src/reskit/soundtrack/engines/echo/engine.rs @@ -309,9 +309,10 @@ pub fn get_events_for_channel( channels: &mut [Channel], active_channel: usize, // Key on or key off note if let Some( note ) = &row.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 ] ); } else { + channels[ active_channel ].note_keyed = true; channels[ active_channel ].active_note = Some( OctaveFrequency { 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 mode == &DcsgChannelMode::Ch3Frequency { 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 - channels[ index ].active_note = channels[ active_channel ].active_note; + // Issue a set frequency for psg3 but don't tell the channel state (matches behaviour in deflemask) + 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 { return Err( "internal error: wtf happened here (3)??" )? } } else { 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 - channels[ index ].active_note = channels[ active_channel ].active_note; + // Issue a set frequency for psg3 but don't tell the channel state (matches behaviour in deflemask) + 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 )? { @@ -554,6 +563,18 @@ pub fn compact_delays( events: Vec ) -> Result, Box Result> { + 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( if channel.id == ESF_FM_6_PCM || channel.id == ESF_PSG_4 { // Generate no events if channel is set to pcm @@ -639,16 +660,15 @@ pub fn get_note_cut( channel: &mut Channel, note_cut_effect: &Effect, tick: u8 ) }; if tick >= after_ticks { - if channel.active_note.is_some() { - channel.active_note = None; - // Consume the note cut after we are done with it - it does not remain active - channel.active_effects = channel.active_effects - .clone() - .into_iter() - .filter( | effect | !( matches!( effect, Effect::NoteCut { after_ticks: _ } ) ) ) - .collect(); - return Ok( vec![ ESF_NOTE_OFF | channel.id ] ); - } + channel.note_keyed = false; + + // Consume the note cut after we are done with it - it does not remain active + channel.active_effects = channel.active_effects + .clone() + .into_iter() + .filter( | effect | !( matches!( effect, Effect::NoteCut { after_ticks: _ } ) ) ) + .collect(); + return Ok( vec![ ESF_NOTE_OFF | channel.id ] ); } // Nothing to generate this tick diff --git a/src/reskit/soundtrack/types.rs b/src/reskit/soundtrack/types.rs index b17506b..e2c8a22 100644 --- a/src/reskit/soundtrack/types.rs +++ b/src/reskit/soundtrack/types.rs @@ -98,6 +98,7 @@ pub struct Channel { pub id: u8, pub active_instrument: Option, pub active_note: Option, + pub note_keyed: bool, pub current_volume: Option, pub active_effects: LinkedHashSet } @@ -144,6 +145,7 @@ impl Channel { id, active_instrument: None, active_note: None, + note_keyed: false, current_volume: None, active_effects: LinkedHashSet::new() }