Getting started with noise generator functions

master
Ashley N. 2023-08-28 00:51:19 -04:00
parent 9d82240445
commit 0714ef5de9
2 changed files with 83 additions and 53 deletions

View File

@ -192,27 +192,29 @@ pub fn get_psg_octave_from_frequency( frequency: i16 ) -> u8 {
/** /**
* Get the setting for the noise generator based on the active noise mode effect. * Get the setting for the noise generator based on the active noise mode effect.
*/ */
pub fn get_noise_generator_setting( note: &Note, noise_mode: Option<&Effect> ) -> Result<u8, Box<dyn Error>> { pub fn get_noise_generator_setting( note: &Note, noise_mode: Option<&Effect> ) -> Result<Option<u8>, Box<dyn Error>> {
Ok( Ok(
if let Some( noise_mode ) = noise_mode { if let Some( noise_mode ) = noise_mode {
if let Effect::DcsgNoiseMode { mode, noise_type } = noise_mode { if let Effect::DcsgNoiseMode { mode, noise_type } = noise_mode {
match noise_type { match noise_type {
NoiseType::PeriodicNoise => match mode { NoiseType::PeriodicNoise => match mode {
DcsgChannelMode::Ch3Frequency => ESF_NOISE_PERIODIC_PSG_3, DcsgChannelMode::Ch3Frequency => Some( ESF_NOISE_PERIODIC_PSG_3 ),
DcsgChannelMode::FixedFrequency => match note { DcsgChannelMode::FixedFrequency => match note {
Note::NoteOff => return Err( "internal error: attempted to get noise generator setting for NoteOff" )?, Note::NoteOff => return Err( "internal error: attempted to get noise generator setting for NoteOff" )?,
Note::C(_) => ESF_NOISE_PERIODIC_LOW, Note::C(_) => Some( ESF_NOISE_PERIODIC_LOW ),
Note::CSharp(_) => ESF_NOISE_PERIODIC_MED, Note::CSharp(_) => Some( ESF_NOISE_PERIODIC_MED ),
Note::D(_) | _ => ESF_NOISE_PERIODIC_HIGH Note::D(_) => Some( ESF_NOISE_PERIODIC_HIGH ),
_ => None
} }
}, },
NoiseType::WhiteNoise => match mode { NoiseType::WhiteNoise => match mode {
DcsgChannelMode::Ch3Frequency => ESF_NOISE_WHITE_PSG_3, DcsgChannelMode::Ch3Frequency => Some( ESF_NOISE_WHITE_PSG_3 ),
DcsgChannelMode::FixedFrequency => match note { DcsgChannelMode::FixedFrequency => match note {
Note::NoteOff => return Err( "internal error: attempted to get noise generator setting for NoteOff" )?, Note::NoteOff => return Err( "internal error: attempted to get noise generator setting for NoteOff" )?,
Note::C(_) => ESF_NOISE_WHITE_LOW, Note::C(_) => Some( ESF_NOISE_WHITE_LOW ),
Note::CSharp(_) => ESF_NOISE_WHITE_MED, Note::CSharp(_) => Some( ESF_NOISE_WHITE_MED ),
Note::D(_) | _ => ESF_NOISE_WHITE_HIGH Note::D(_) => Some( ESF_NOISE_WHITE_HIGH ),
_ => None
} }
} }
} }
@ -222,7 +224,7 @@ pub fn get_noise_generator_setting( note: &Note, noise_mode: Option<&Effect> ) -
} else { } else {
match note { match note {
Note::NoteOff => return Err( "internal error: attempted to get noise generator setting for NoteOff" )?, Note::NoteOff => return Err( "internal error: attempted to get noise generator setting for NoteOff" )?,
_ => ESF_NOISE_WHITE_PSG_3 _ => Some( ESF_NOISE_WHITE_PSG_3 )
} }
} }
) )
@ -272,34 +274,34 @@ pub fn get_delay( delay: u8 ) -> Result<EchoEvent, Box<dyn Error>> {
* For a specific row and channel, get the events this row and channel contribute to the stream. * For a specific row and channel, get the events this row and channel contribute to the stream.
* While doing so, update the state of the channel for future event generation. * While doing so, update the state of the channel for future event generation.
*/ */
pub fn get_events_for_channel( channel: &mut Channel, row: &PatternRow, pcm_offset: u8, default_psg_instr_index: Option<u16> ) -> Result<Vec<EchoEvent>, Box<dyn Error>> { pub fn get_events_for_channel( channels: &mut [Channel], active_channel: usize, row: &PatternRow, pcm_offset: u8, default_psg_instr_index: Option<u16> ) -> Result<Vec<EchoEvent>, Box<dyn Error>> {
let mut events: Vec<EchoEvent> = Vec::new(); let mut events: Vec<EchoEvent> = Vec::new();
// Adjust volume // Adjust volume
if let Some( volume ) = &row.volume { if let Some( volume ) = &row.volume {
// https://github.com/sikthehedgehog/Echo/blob/master/doc/esf.txt#L206-L207 // https://github.com/sikthehedgehog/Echo/blob/master/doc/esf.txt#L206-L207
let volume = get_volume( channel.id, *volume )?; let volume = get_volume( channels[ active_channel ].id, *volume )?;
channel.current_volume = Some( volume ); channels[ active_channel ].current_volume = Some( volume );
events.push( vec![ ESF_SET_VOLUME | channel.id, volume ] ); events.push( vec![ ESF_SET_VOLUME | channels[ active_channel ].id, volume ] );
} }
// Set the instrument // Set the instrument
if let Some( instrument ) = &row.instrument_index { if let Some( instrument ) = &row.instrument_index {
// Do not set the same instrument if it was already set before // Do not set the same instrument if it was already set before
if &row.instrument_index != &channel.active_instrument { if &row.instrument_index != &channels[ active_channel ].active_instrument {
events.push( vec![ ESF_SET_INSTRUMENT | channel.id, *instrument as u8 ] ); events.push( vec![ ESF_SET_INSTRUMENT | channels[ active_channel ].id, *instrument as u8 ] );
channel.active_instrument = Some( *instrument ); channels[ active_channel ].active_instrument = Some( *instrument );
} }
} else { } else {
// This is SN1, SN2, SN3, or SN4 with no active instrument // This is SN1, SN2, SN3, or SN4 with no active instrument
// Check if the channel needs "__reskit_default_psg_instrument" set before a note is set // Check if the channel needs "__reskit_default_psg_instrument" set before a note is set
if channel.active_instrument.is_none() && ( ESF_PSG_1..=ESF_PSG_4 ).contains( &channel.id ) { if channels[ active_channel ].active_instrument.is_none() && ( ESF_PSG_1..=ESF_PSG_4 ).contains( &channels[ active_channel ].id ) {
if row.note.is_some() { if row.note.is_some() {
// Set "__reskit_default_psg_instrument" // Set "__reskit_default_psg_instrument"
let instrument = default_psg_instr_index.ok_or( "internal error: no default psg instrument to apply" )?; let instrument = default_psg_instr_index.ok_or( "internal error: no default psg instrument to apply" )?;
events.push( vec![ ESF_SET_INSTRUMENT | channel.id, instrument as u8 ] ); events.push( vec![ ESF_SET_INSTRUMENT | channels[ active_channel ].id, instrument as u8 ] );
channel.active_instrument = Some( instrument ); channels[ active_channel ].active_instrument = Some( instrument );
} }
} }
} }
@ -307,34 +309,61 @@ pub fn get_events_for_channel( channel: &mut Channel, row: &PatternRow, pcm_offs
// 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 {
channel.active_note = None; channels[ active_channel ].active_note = None;
events.push( vec![ ESF_NOTE_OFF | channel.id ] ); events.push( vec![ ESF_NOTE_OFF | channels[ active_channel ].id ] );
} else { } else {
channel.active_note = Some( channels[ active_channel ].active_note = Some(
OctaveFrequency { OctaveFrequency {
octave: note.get_octave()?, octave: note.get_octave()?,
frequency: if ( ESF_PSG_1..=ESF_PSG_3 ).contains( &channel.id ) { frequency: if ( ESF_PSG_1..=ESF_PSG_4 ).contains( &channels[ active_channel ].id ) {
get_psg_semitone_frequency( note.get_octave()?, get_semitone( note )? )? get_psg_semitone_frequency( note.get_octave()?, get_semitone( note )? )?
} else if channel.id == ESF_PSG_4 {
// probably doesn't matter a damn what we put here, the OctaveFrequency is used only for portamentos.
// and you can't portamento on PSG_4 (you can, however, portamento the frequency set on PSG_3, but
// we'll get to cross-channel generated events in a bit.)
0
} else { } else {
get_fm_semitone_frequency( get_semitone( note )? )? get_fm_semitone_frequency( get_semitone( note )? )?
} }
} }
); );
if channel.id == ESF_FM_6_PCM { if channels[ active_channel ].id == ESF_FM_6_PCM {
events.push( vec![ ESF_NOTE_ON | channel.id, get_pcm_index( note )? + pcm_offset ] ); events.push( vec![ ESF_NOTE_ON | channels[ active_channel ].id, get_pcm_index( note )? + pcm_offset ] );
} else if channel.id == ESF_PSG_4 { } else if channels[ active_channel ].id == ESF_PSG_4 {
// Find the single (and it should only ever be a single) Effect::DcsgNoiseMode attached to the channel // Find the single (and it should only ever be a single) Effect::DcsgNoiseMode attached to the channel
let dcsg_noise_mode = channel.active_effects.iter().find( | effect | matches!( effect, Effect::DcsgNoiseMode { mode: _, noise_type: _ } ) ); let dcsg_noise_mode = channels[ active_channel ].active_effects.iter().find( | effect | matches!( effect, Effect::DcsgNoiseMode { mode: _, noise_type: _ } ) );
events.push( vec![ ESF_NOTE_ON | channel.id, get_noise_generator_setting( note, dcsg_noise_mode )? ] );
// Do we need to copy channel.active_note to psg3 and set its frequency? psg3 sets the actual note played for psg4 in special circumstances
if let Some( dcsg_noise_mode ) = dcsg_noise_mode {
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
events.push( vec![
ESF_SET_FREQUENCY | channels[ index ].id,
( 0x000F & channels[ index ].active_note.ok_or( "internal error: wtf happened here (1)??" )?.frequency ) as u8,
( ( 0x3F0 & channels[ index ].active_note.ok_or( "internal error: wtf happened here (2)??" )?.frequency ) >> 4 ) as u8
] );
}
} else { } else {
let note = get_note( note, channel.id )?; return Err( "internal error: wtf happened here (3)??" )?
events.push( vec![ ESF_NOTE_ON | channel.id, note ] ); }
} else {
let index = channels.iter().position( | channel | channel.id == ESF_PSG_3 ).ok_or( "internal error: where is psg3??" )?;
// Copy over the active note
channels[ index ].active_note = channels[ active_channel ].active_note;
// Issue a set frequency for psg3
events.push( vec![
ESF_SET_FREQUENCY | channels[ index ].id,
( 0x000F & channels[ index ].active_note.ok_or( "internal error: wtf happened here (1)??" )?.frequency ) as u8,
( ( 0x3F0 & channels[ index ].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 )? {
events.push( vec![ ESF_NOTE_ON | channels[ active_channel ].id, noise_generator_setting ] );
}
} else {
let note = get_note( note, channels[ active_channel ].id )?;
events.push( vec![ ESF_NOTE_ON | channels[ active_channel ].id, note ] );
} }
} }
} }
@ -738,7 +767,7 @@ pub fn get_events_for_row( channels: &mut [Channel], instruments: &Vec<Instrumen
events.extend( apply_effects_to_channel( &mut channels[ i ], &subrows[ i ].effects )? ); events.extend( apply_effects_to_channel( &mut channels[ i ], &subrows[ i ].effects )? );
// Get the ESF events for this channel's part of the row // Get the ESF events for this channel's part of the row
events.extend( get_events_for_channel( &mut channels[ i ], subrows[ i ], pcm_offset, default_psg_instr_index )? ); events.extend( get_events_for_channel( channels, i, subrows[ i ], pcm_offset, default_psg_instr_index )? );
} }
Ok( get_delays( events, channels, ticks_to_wait )? ) Ok( get_delays( events, channels, ticks_to_wait )? )

View File

@ -469,19 +469,19 @@ impl DmfModule {
// check: do these octave shifts make sense for all dmf modules? // check: do these octave shifts make sense for all dmf modules?
// they were needed on the test dmf but no documentation supports it // they were needed on the test dmf but no documentation supports it
// test dmf sounds off key otherwise... // test dmf sounds off key otherwise...
1 => Note::CSharp( if channel > 5 { octave - 1 } else { octave } ), 1 => Note::CSharp( if (6..9).contains( &channel ) { octave - 1 } else { octave } ),
2 => Note::D( if channel > 5 { octave - 1 } else { octave } ), 2 => Note::D( if (6..9).contains( &channel ) { octave - 1 } else { octave } ),
3 => Note::DSharp( if channel > 5 { octave - 1 } else { octave } ), 3 => Note::DSharp( if (6..9).contains( &channel ) { octave - 1 } else { octave } ),
4 => Note::E( if channel > 5 { octave - 1 } else { octave } ), 4 => Note::E( if (6..9).contains( &channel ) { octave - 1 } else { octave } ),
5 => Note::F( if channel > 5 { octave - 1 } else { octave } ), 5 => Note::F( if (6..9).contains( &channel ) { octave - 1 } else { octave } ),
6 => Note::FSharp( if channel > 5 { octave - 1 } else { octave } ), 6 => Note::FSharp( if (6..9).contains( &channel ) { octave - 1 } else { octave } ),
7 => Note::G( if channel > 5 { octave - 1 } else { octave } ), 7 => Note::G( if (6..9).contains( &channel ) { octave - 1 } else { octave } ),
8 => Note::GSharp( if channel > 5 { octave - 1 } else { octave } ), 8 => Note::GSharp( if (6..9).contains( &channel ) { octave - 1 } else { octave } ),
9 => Note::A( if channel > 5 { octave - 1 } else { octave } ), 9 => Note::A( if (6..9).contains( &channel ) { octave - 1 } else { octave } ),
10 => Note::ASharp( if channel > 5 { octave - 1 } else { octave } ), 10 => Note::ASharp( if (6..9).contains( &channel ) { octave - 1 } else { octave } ),
11 => Note::B( if channel > 5 { octave - 1 } else { octave } ), 11 => Note::B( if (6..9).contains( &channel ) { octave - 1 } else { octave } ),
12 => Note::C( if channel > 5 { octave } else { octave + 1 } ), // deflemask y u shift the octave down 1 for C?? 12 => Note::C( if (6..9).contains( &channel ) { octave } else { octave + 1 } ), // deflemask y u shift the octave down 1 for C??
0 => Note::C( if channel > 5 { octave - 1 } else { octave } ), // deflemask y u do this?? 0 is not documented 0 => Note::C( if (6..9).contains( &channel ) { octave - 1 } else { octave } ), // deflemask y u do this?? 0 is not documented
_ => return Err( format!( "invalid file: invalid note id {}", note ) )? _ => return Err( format!( "invalid file: invalid note id {}", note ) )?
} }
) )
@ -665,13 +665,14 @@ impl DmfModule {
} }
pub fn uses_default_psg( channel_patterns: &Vec<Vec<PatternRow>> ) -> Result<bool, Box<dyn Error>> { pub fn uses_default_psg( channel_patterns: &Vec<Vec<PatternRow>> ) -> Result<bool, Box<dyn Error>> {
let mut channels: [Channel; 3] = [ let mut channels: [Channel; 4] = [
Channel::new( 1 ), Channel::new( 1 ),
Channel::new( 2 ), Channel::new( 2 ),
Channel::new( 3 ) Channel::new( 3 ),
Channel::new( 4 )
]; ];
for channel_id in 6..9 { for channel_id in 6..=9 {
let channel_patterns = &channel_patterns[ channel_id ]; let channel_patterns = &channel_patterns[ channel_id ];
for row in channel_patterns { for row in channel_patterns {
// If a set instrument is encountered, just set the instrument on the channel // If a set instrument is encountered, just set the instrument on the channel