Instruments import

master
Ashley N. 2023-08-13 13:45:13 -04:00
parent ff2d2a1a24
commit 48f606f637
1 changed files with 366 additions and 7 deletions

View File

@ -1,4 +1,4 @@
use std::{error::Error, fs::File, io::Read, str::from_utf8, slice::Iter, convert::TryInto}; use std::{error::Error, fs::File, io::Read, str::from_utf8, slice::Iter, convert::TryInto, collections::HashMap};
use flate2::read::ZlibDecoder; use flate2::read::ZlibDecoder;
const DMF_MAGIC_NUMBER: &'static str = ".DelekDefleMask."; const DMF_MAGIC_NUMBER: &'static str = ".DelekDefleMask.";
@ -6,6 +6,12 @@ const DMF_SUPPORTED_VERSION: u8 = 0x18;
const DMF_MD: u8 = 0x02; const DMF_MD: u8 = 0x02;
const DMF_MD_ENHANCED_CH3: u8 = 0x42; const DMF_MD_ENHANCED_CH3: u8 = 0x42;
#[derive(Debug)]
pub enum Either< Type1, Type2 > {
Type1( Type1 ),
Type2( Type2 )
}
#[derive(Debug)] #[derive(Debug)]
pub enum FrameMode { pub enum FrameMode {
Ntsc, Ntsc,
@ -13,6 +19,58 @@ pub enum FrameMode {
Custom( u8, u8, u8 ) Custom( u8, u8, u8 )
} }
#[derive(Debug, Default)]
pub struct FmOperator {
am: u8,
ar: u8,
dr: u8,
mult: u8,
rr: u8,
sl: u8,
tl: u8,
dt2: u8,
rs: u8,
dt: i8,
d2r: u8,
ssg_mode: u8
}
#[derive(Debug)]
pub struct FmSettings {
alg: u8,
fb: u8,
fms: u8,
ams: u8,
operators: [FmOperator; 4]
}
#[derive(Debug)]
pub struct PsgEnvelope {
envelope: Either<Vec<u32>, Vec<i32>>,
loop_at: Option<usize>,
settings: HashMap<&'static str, bool>
}
#[derive(Debug)]
pub struct PsgSettings {
volume: PsgEnvelope,
arpeggio: PsgEnvelope,
noise: PsgEnvelope,
wavetable: PsgEnvelope
}
#[derive(Debug)]
pub enum InstrumentType {
Fm( FmSettings ),
Psg( PsgSettings )
}
#[derive(Debug)]
pub struct Instrument {
name: String,
instrument_type: InstrumentType
}
pub struct DmfModule { pub struct DmfModule {
platform: u8, platform: u8,
version: u8, version: u8,
@ -21,7 +79,8 @@ pub struct DmfModule {
speed_b: u8, speed_b: u8,
frame_mode: FrameMode, frame_mode: FrameMode,
rows_per_pattern: u32, rows_per_pattern: u32,
patterns: Vec<Vec<u8>> pattern_matrix: Vec<Vec<u8>>,
instruments: Vec<Instrument>
} }
fn get_string( bytes: &mut Iter<'_, u8>, take: usize ) -> Result<String, Box<dyn Error>> { fn get_string( bytes: &mut Iter<'_, u8>, take: usize ) -> Result<String, Box<dyn Error>> {
@ -38,6 +97,12 @@ fn get_u8( bytes: &mut Iter<'_, u8> ) -> Result<u8, Box<dyn Error>> {
Ok( took ) Ok( took )
} }
fn get_i8( bytes: &mut Iter<'_, u8> ) -> Result<i8, Box<dyn Error>> {
let took = bytes.take( 1 ).cloned().next().ok_or( "invalid file: expected 1 byte" )?;
Ok( took as i8 )
}
fn get_u32( bytes: &mut Iter<'_, u8> ) -> Result<u32, Box<dyn Error>> { fn get_u32( bytes: &mut Iter<'_, u8> ) -> Result<u32, Box<dyn Error>> {
let took = bytes.take( 4 ); let took = bytes.take( 4 );
let took: Vec<u8> = took.cloned().collect(); let took: Vec<u8> = took.cloned().collect();
@ -46,8 +111,16 @@ fn get_u32( bytes: &mut Iter<'_, u8> ) -> Result<u32, Box<dyn Error>> {
Ok( took ) Ok( took )
} }
fn get_i32( bytes: &mut Iter<'_, u8> ) -> Result<i32, Box<dyn Error>> {
let took = bytes.take( 4 );
let took: Vec<u8> = took.cloned().collect();
let took = i32::from_le_bytes( took[0..4].try_into()? );
Ok( took )
}
fn skip( bytes: &mut Iter<'_, u8>, by: usize ) { fn skip( bytes: &mut Iter<'_, u8>, by: usize ) {
for i in 0..by { for _i in 0..by {
bytes.next(); bytes.next();
} }
} }
@ -139,16 +212,16 @@ impl DmfModule {
13 13
}; };
let mut patterns: Vec<Vec<u8>> = vec![vec![0; system_total_channels]; patterns_count.into()]; let mut pattern_matrix: Vec<Vec<u8>> = vec![vec![0; system_total_channels]; patterns_count.into()];
for channel in 0..system_total_channels { for channel in 0..system_total_channels {
for pattern in 0..patterns_count { for pattern in 0..patterns_count {
let channel: usize = channel.into(); let channel: usize = channel.into();
let pattern: usize = pattern.into(); let pattern: usize = pattern.into();
patterns[ pattern ][ channel ] = get_u8( bytes.by_ref() )?; pattern_matrix[ pattern ][ channel ] = get_u8( bytes.by_ref() )?;
} }
} }
for pattern in &patterns { for pattern in &pattern_matrix {
for channel in pattern { for channel in pattern {
print!( "{:#04X?} ", channel ); print!( "{:#04X?} ", channel );
} }
@ -157,10 +230,296 @@ impl DmfModule {
print!( "\n" ); print!( "\n" );
let mut instruments: Vec<Instrument> = Vec::new();
let instrument_count = get_u8( bytes.by_ref() )?;
println!( "Instruments:\t{}", instrument_count );
for i in 0..instrument_count {
let name_len = get_u8( bytes.by_ref() )?;
let name = get_string( bytes.by_ref(), name_len.into() )?;
println!( "Instrument {}:\t{}", i, name );
let mode = get_u8( bytes.by_ref() )?;
let instrument_type = match mode {
0 => {
println!( "Psg Instrument" );
// Volume envelope
let volume = {
let size = get_u8( bytes.by_ref() )?;
let mut envelope: Vec<u32> = Vec::new();
for _i in 0..size {
envelope.push( get_u32( bytes.by_ref() )? );
}
let loop_at: Option<usize> = if size > 0 {
let loop_position = get_i8( bytes.by_ref() )?;
if loop_position != -1 {
Some( loop_position.try_into()? )
} else {
None
}
} else {
None
};
println!( "Volume Envelope Size:\t{}", envelope.len() );
PsgEnvelope {
envelope: Either::Type1( envelope ),
loop_at,
settings: HashMap::new()
}
};
// Arpeggio envelope
let arpeggio = {
let size = get_u8( bytes.by_ref() )?;
let mut envelope: Vec<i32> = Vec::new();
for _i in 0..size {
envelope.push( get_i32( bytes.by_ref() )? - 12 );
}
let loop_at: Option<usize> = if size > 0 {
let loop_position = get_i8( bytes.by_ref() )?;
if loop_position != -1 {
Some( loop_position.try_into()? )
} else {
None
}
} else {
None
};
let settings = HashMap::from([
( "arpeggio_macro_fixed", get_u8( bytes.by_ref() )? == 1 )
]);
println!( "Arpeggio Envelope Size:\t{}", envelope.len() );
println!( "Arpeggio Macro Fixed:\t{}", settings[ "arpeggio_macro_fixed" ] );
PsgEnvelope {
envelope: Either::Type2( envelope ),
loop_at,
settings
}
};
// Noise envelope
let noise = {
let size = get_u8( bytes.by_ref() )?;
let mut envelope: Vec<u32> = Vec::new();
for _i in 0..size {
envelope.push( get_u32( bytes.by_ref() )? );
}
let loop_at: Option<usize> = if size > 0 {
let loop_position = get_i8( bytes.by_ref() )?;
if loop_position != -1 {
Some( loop_position.try_into()? )
} else {
None
}
} else {
None
};
println!( "Noise Envelope Size:\t{}", envelope.len() );
PsgEnvelope {
envelope: Either::Type1( envelope ),
loop_at,
settings: HashMap::new()
}
};
// Wavetable envelope
let wavetable = {
let size = get_u8( bytes.by_ref() )?;
let mut envelope: Vec<u32> = Vec::new();
for _i in 0..size {
envelope.push( get_u32( bytes.by_ref() )? );
}
let loop_at: Option<usize> = if size > 0 {
let loop_position = get_i8( bytes.by_ref() )?;
if loop_position != -1 {
Some( loop_position.try_into()? )
} else {
None
}
} else {
None
};
println!( "WavTbl Envelope Size:\t{}\n", envelope.len() );
PsgEnvelope {
envelope: Either::Type1( envelope ),
loop_at,
settings: HashMap::new()
}
};
InstrumentType::Psg( PsgSettings { volume, arpeggio, noise, wavetable } )
},
1 => {
println!( "Fm Instrument" );
let alg = get_u8( bytes.by_ref() )?;
let fb = get_u8( bytes.by_ref() )?;
let fms = get_u8( bytes.by_ref() )?;
let ams = get_u8( bytes.by_ref() )?;
println!( "Alg:\t{}", alg );
println!( "Fb:\t{}", fb );
println!( "FMS:\t{}", fms );
println!( "AMS:\t{}", ams );
let mut operators: [FmOperator; 4] = [
FmOperator::default(),
FmOperator::default(),
FmOperator::default(),
FmOperator::default()
];
// Operator 1
{
operators[ 0 ].am = get_u8( bytes.by_ref() )?;
operators[ 0 ].ar = get_u8( bytes.by_ref() )?;
operators[ 0 ].dr = get_u8( bytes.by_ref() )?;
operators[ 0 ].mult = get_u8( bytes.by_ref() )?;
operators[ 0 ].rr = get_u8( bytes.by_ref() )?;
operators[ 0 ].sl = get_u8( bytes.by_ref() )?;
operators[ 0 ].tl = get_u8( bytes.by_ref() )?;
operators[ 0 ].dt2 = get_u8( bytes.by_ref() )?;
operators[ 0 ].rs = get_u8( bytes.by_ref() )?;
operators[ 0 ].dt = get_i8( bytes.by_ref() )? - 3;
operators[ 0 ].d2r = get_u8( bytes.by_ref() )?;
operators[ 0 ].ssg_mode = get_u8( bytes.by_ref() )?;
println!( "Op 1 AM:\t{}", operators[ 0 ].am );
println!( "Op 1 AR:\t{}", operators[ 0 ].ar );
println!( "Op 1 DR:\t{}", operators[ 0 ].dr );
println!( "Op 1 MULT:\t{}", operators[ 0 ].mult );
println!( "Op 1 RR:\t{}", operators[ 0 ].rr );
println!( "Op 1 SL:\t{}", operators[ 0 ].sl );
println!( "Op 1 TL:\t{}", operators[ 0 ].tl );
println!( "Op 1 DT2:\t{}", operators[ 0 ].dt2 );
println!( "Op 1 RS:\t{}", operators[ 0 ].rs );
println!( "Op 1 DT:\t{}", operators[ 0 ].dt );
println!( "Op 1 D2R:\t{}", operators[ 0 ].d2r );
println!( "Op 1 SSG_MODE:\t{}\n", operators[ 0 ].ssg_mode );
}
// Operator 3
{
operators[ 2 ].am = get_u8( bytes.by_ref() )?;
operators[ 2 ].ar = get_u8( bytes.by_ref() )?;
operators[ 2 ].dr = get_u8( bytes.by_ref() )?;
operators[ 2 ].mult = get_u8( bytes.by_ref() )?;
operators[ 2 ].rr = get_u8( bytes.by_ref() )?;
operators[ 2 ].sl = get_u8( bytes.by_ref() )?;
operators[ 2 ].tl = get_u8( bytes.by_ref() )?;
operators[ 2 ].dt2 = get_u8( bytes.by_ref() )?;
operators[ 2 ].rs = get_u8( bytes.by_ref() )?;
operators[ 2 ].dt = get_i8( bytes.by_ref() )? - 3;
operators[ 2 ].d2r = get_u8( bytes.by_ref() )?;
operators[ 2 ].ssg_mode = get_u8( bytes.by_ref() )?;
println!( "Op 3 AM:\t{}", operators[ 2 ].am );
println!( "Op 3 AR:\t{}", operators[ 2 ].ar );
println!( "Op 3 DR:\t{}", operators[ 2 ].dr );
println!( "Op 3 MULT:\t{}", operators[ 2 ].mult );
println!( "Op 3 RR:\t{}", operators[ 2 ].rr );
println!( "Op 3 SL:\t{}", operators[ 2 ].sl );
println!( "Op 3 TL:\t{}", operators[ 2 ].tl );
println!( "Op 3 DT2:\t{}", operators[ 2 ].dt2 );
println!( "Op 3 RS:\t{}", operators[ 2 ].rs );
println!( "Op 3 DT:\t{}", operators[ 2 ].dt );
println!( "Op 3 D2R:\t{}", operators[ 2 ].d2r );
println!( "Op 3 SSG_MODE:\t{}\n", operators[ 2 ].ssg_mode );
}
// Operator 2
{
operators[ 1 ].am = get_u8( bytes.by_ref() )?;
operators[ 1 ].ar = get_u8( bytes.by_ref() )?;
operators[ 1 ].dr = get_u8( bytes.by_ref() )?;
operators[ 1 ].mult = get_u8( bytes.by_ref() )?;
operators[ 1 ].rr = get_u8( bytes.by_ref() )?;
operators[ 1 ].sl = get_u8( bytes.by_ref() )?;
operators[ 1 ].tl = get_u8( bytes.by_ref() )?;
operators[ 1 ].dt2 = get_u8( bytes.by_ref() )?;
operators[ 1 ].rs = get_u8( bytes.by_ref() )?;
operators[ 1 ].dt = get_i8( bytes.by_ref() )? - 3;
operators[ 1 ].d2r = get_u8( bytes.by_ref() )?;
operators[ 1 ].ssg_mode = get_u8( bytes.by_ref() )?;
println!( "Op 2 AM:\t{}", operators[ 1 ].am );
println!( "Op 2 AR:\t{}", operators[ 1 ].ar );
println!( "Op 2 DR:\t{}", operators[ 1 ].dr );
println!( "Op 2 MULT:\t{}", operators[ 1 ].mult );
println!( "Op 2 RR:\t{}", operators[ 1 ].rr );
println!( "Op 2 SL:\t{}", operators[ 1 ].sl );
println!( "Op 2 TL:\t{}", operators[ 1 ].tl );
println!( "Op 2 DT2:\t{}", operators[ 1 ].dt2 );
println!( "Op 2 RS:\t{}", operators[ 1 ].rs );
println!( "Op 2 DT:\t{}", operators[ 1 ].dt );
println!( "Op 2 D2R:\t{}", operators[ 1 ].d2r );
println!( "Op 2 SSG_MODE:\t{}\n", operators[ 1 ].ssg_mode );
}
// Operator 4
{
operators[ 3 ].am = get_u8( bytes.by_ref() )?;
operators[ 3 ].ar = get_u8( bytes.by_ref() )?;
operators[ 3 ].dr = get_u8( bytes.by_ref() )?;
operators[ 3 ].mult = get_u8( bytes.by_ref() )?;
operators[ 3 ].rr = get_u8( bytes.by_ref() )?;
operators[ 3 ].sl = get_u8( bytes.by_ref() )?;
operators[ 3 ].tl = get_u8( bytes.by_ref() )?;
operators[ 3 ].dt2 = get_u8( bytes.by_ref() )?;
operators[ 3 ].rs = get_u8( bytes.by_ref() )?;
operators[ 3 ].dt = get_i8( bytes.by_ref() )? - 3;
operators[ 3 ].d2r = get_u8( bytes.by_ref() )?;
operators[ 3 ].ssg_mode = get_u8( bytes.by_ref() )?;
println!( "Op 4 AM:\t{}", operators[ 3 ].am );
println!( "Op 4 AR:\t{}", operators[ 3 ].ar );
println!( "Op 4 DR:\t{}", operators[ 3 ].dr );
println!( "Op 4 MULT:\t{}", operators[ 3 ].mult );
println!( "Op 4 RR:\t{}", operators[ 3 ].rr );
println!( "Op 4 SL:\t{}", operators[ 3 ].sl );
println!( "Op 4 TL:\t{}", operators[ 3 ].tl );
println!( "Op 4 DT2:\t{}", operators[ 3 ].dt2 );
println!( "Op 4 RS:\t{}", operators[ 3 ].rs );
println!( "Op 4 DT:\t{}", operators[ 3 ].dt );
println!( "Op 4 D2R:\t{}", operators[ 3 ].d2r );
println!( "Op 4 SSG_MODE:\t{}\n", operators[ 3 ].ssg_mode );
}
InstrumentType::Fm( FmSettings { alg, fb, fms, ams, operators } )
},
_ => return Err( format!( "invalid file: invalid instrument mode {}", mode ) )?
};
instruments.push( Instrument { name, instrument_type } );
}
// TODO !! // TODO !!
Ok( Ok(
DmfModule { platform, version, time_base, speed_a, speed_b, frame_mode, rows_per_pattern, patterns } DmfModule {
platform, version, time_base, speed_a, speed_b, frame_mode, rows_per_pattern,
pattern_matrix, instruments
}
) )
} }