Ability to use PSG channels without defined instrument in track
parent
a1eb158292
commit
2f84d47d99
|
@ -2,7 +2,7 @@ use std::{collections::HashMap, cmp::{max, min}, error::Error};
|
|||
use convert_case::{Case, Casing};
|
||||
use samplerate::convert;
|
||||
use uuid::Uuid;
|
||||
use crate::reskit::{soundtrack::{formats::dmf::{DmfModule, ECHO_EWF_SAMPLE_RATE}, types::{InstrumentType, SampleFormat, Channel, PatternRow}}, utility::{print_warning, Ring}};
|
||||
use crate::reskit::{soundtrack::{formats::dmf::{DmfModule, ECHO_EWF_SAMPLE_RATE}, types::{InstrumentType, SampleFormat, Channel, PatternRow}}, utility::{print_warning, Ring, print_info}};
|
||||
use super::engine::{EchoFormat, ESF_FM_1, ESF_FM_2, ESF_FM_3, ESF_FM_4, ESF_FM_5, ESF_FM_6, ESF_PSG_1, ESF_PSG_2, ESF_PSG_3, ESF_PSG_4, EchoEvent, get_events_for_row, compact_delays};
|
||||
|
||||
|
||||
|
@ -88,6 +88,16 @@ impl EchoFormat for DmfModule {
|
|||
let mut volume_envelope: Vec<u8> = settings.volume.envelope.iter().map( | long | *long as u8 ).collect();
|
||||
let mut arpeggio_envelope: Vec<i8> = settings.arpeggio.envelope.iter().map( | long | *long as i8 ).collect();
|
||||
|
||||
// Validations (this makes my life easier when dmf format changes again)
|
||||
if volume_envelope.is_empty() {
|
||||
// Push one max volume if there is no volume defined in this instrument
|
||||
volume_envelope.push( 0x0F );
|
||||
}
|
||||
if arpeggio_envelope.is_empty() {
|
||||
// Push one byte of no arpeggio shift if no arpeggio is defined in this instrument
|
||||
arpeggio_envelope.push( 0x00 );
|
||||
}
|
||||
|
||||
// now take a slice of the repeatable portion of the smaller array,
|
||||
// and use it to expand the smaller array to the same size as the
|
||||
// larger array. if there is no repeatable portion, take a one-element
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use std::{error::Error, fs::File, io::Read, convert::TryInto, collections::HashMap};
|
||||
use flate2::read::ZlibDecoder;
|
||||
use linked_hash_set::LinkedHashSet;
|
||||
use crate::reskit::{utility::{get_string, get_u8, skip, get_u32, get_i8, get_i32, get_u16, get_i16, print_info}, soundtrack::types::{SampleFormat, PsgEnvelope, Note, Sample, PsgSettings, PatternRow, Effect, DcsgChannelMode, NoiseType, Instrument, InstrumentType, Fm2612Operator, Fm2612Settings}};
|
||||
use crate::reskit::{utility::{get_string, get_u8, skip, get_u32, get_i8, get_i32, get_u16, get_i16, print_info}, soundtrack::types::{SampleFormat, PsgEnvelope, Note, Sample, PsgSettings, PatternRow, Effect, DcsgChannelMode, NoiseType, Instrument, InstrumentType, Fm2612Operator, Fm2612Settings, Channel}};
|
||||
|
||||
const DMF_MAGIC_NUMBER: &'static str = ".DelekDefleMask.";
|
||||
const DMF_SUPPORTED_VERSION: u8 = 27;
|
||||
|
@ -432,7 +432,7 @@ impl DmfModule {
|
|||
_ => return Err( format!( "invalid file: invalid instrument mode {}", mode ) )?
|
||||
};
|
||||
|
||||
instruments.push( Instrument { index: i as usize, name, instrument_type } );
|
||||
instruments.push( Instrument { name, instrument_type } );
|
||||
}
|
||||
|
||||
// Version 27 of DMF specifies "1 wavetable of 0 bytes" for sega megadrive
|
||||
|
@ -581,6 +581,40 @@ impl DmfModule {
|
|||
channel_patterns.push( channel_rows );
|
||||
}
|
||||
|
||||
// If at least one PSG channel never defines an instrument, insert the default PSG instrument
|
||||
// which is a repeat of zero attentuation.
|
||||
print_info( "Default PSG instruments:" );
|
||||
if DmfModule::uses_default_psg( &channel_patterns )? {
|
||||
print_info( "One or more channels use the default PSG instrument" );
|
||||
instruments.push( Instrument{
|
||||
name: format!( "Default PSG Instrument" ),
|
||||
instrument_type: InstrumentType::PsgDcsg( PsgSettings {
|
||||
volume: PsgEnvelope {
|
||||
envelope: vec![ 0x0F as u32 ],
|
||||
loop_at: Some( 0 ),
|
||||
settings: HashMap::new()
|
||||
},
|
||||
arpeggio: PsgEnvelope {
|
||||
envelope: vec![],
|
||||
loop_at: None,
|
||||
settings: HashMap::new()
|
||||
},
|
||||
noise: PsgEnvelope {
|
||||
envelope: vec![],
|
||||
loop_at: None,
|
||||
settings: HashMap::new()
|
||||
},
|
||||
wavetable: PsgEnvelope {
|
||||
envelope: vec![],
|
||||
loop_at: None,
|
||||
settings: HashMap::new()
|
||||
}
|
||||
} )
|
||||
} )
|
||||
} else {
|
||||
print_info( "All PSG channels set instruments" );
|
||||
}
|
||||
|
||||
print_info( "PCM Samples:" );
|
||||
let mut samples: Vec<Sample> = Vec::new();
|
||||
let num_samples = get_u8( bytes.by_ref() )?;
|
||||
|
@ -629,4 +663,32 @@ impl DmfModule {
|
|||
)
|
||||
}
|
||||
|
||||
pub fn uses_default_psg( channel_patterns: &Vec<Vec<PatternRow>> ) -> Result<bool, Box<dyn Error>> {
|
||||
let mut channels: [Channel; 3] = [
|
||||
Channel::new( 1 ),
|
||||
Channel::new( 2 ),
|
||||
Channel::new( 3 )
|
||||
];
|
||||
|
||||
for channel_id in 6..9 {
|
||||
let channel_patterns = &channel_patterns[ channel_id ];
|
||||
for row in channel_patterns {
|
||||
// If a set instrument is encountered, just set the instrument on the channel
|
||||
// We will check all three channels to see if at least one does not contain
|
||||
// an active instrument.
|
||||
if row.instrument_index.is_some() {
|
||||
channels[ channel_id - 6 ].active_instrument = Some( 0 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for channel in channels {
|
||||
if channel.active_instrument.is_none() {
|
||||
return Ok( true )
|
||||
}
|
||||
}
|
||||
|
||||
Ok( false )
|
||||
}
|
||||
|
||||
}
|
|
@ -50,7 +50,6 @@ pub enum InstrumentType {
|
|||
|
||||
#[derive(Debug)]
|
||||
pub struct Instrument {
|
||||
pub index: usize,
|
||||
pub name: String,
|
||||
pub instrument_type: InstrumentType
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue