Instruments import
parent
ff2d2a1a24
commit
48f606f637
|
@ -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;
|
||||
|
||||
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_ENHANCED_CH3: u8 = 0x42;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Either< Type1, Type2 > {
|
||||
Type1( Type1 ),
|
||||
Type2( Type2 )
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum FrameMode {
|
||||
Ntsc,
|
||||
|
@ -13,6 +19,58 @@ pub enum FrameMode {
|
|||
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 {
|
||||
platform: u8,
|
||||
version: u8,
|
||||
|
@ -21,7 +79,8 @@ pub struct DmfModule {
|
|||
speed_b: u8,
|
||||
frame_mode: FrameMode,
|
||||
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>> {
|
||||
|
@ -38,6 +97,12 @@ fn get_u8( bytes: &mut Iter<'_, u8> ) -> Result<u8, Box<dyn Error>> {
|
|||
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>> {
|
||||
let took = bytes.take( 4 );
|
||||
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 )
|
||||
}
|
||||
|
||||
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 ) {
|
||||
for i in 0..by {
|
||||
for _i in 0..by {
|
||||
bytes.next();
|
||||
}
|
||||
}
|
||||
|
@ -139,16 +212,16 @@ impl DmfModule {
|
|||
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 pattern in 0..patterns_count {
|
||||
let channel: usize = channel.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 {
|
||||
print!( "{:#04X?} ", channel );
|
||||
}
|
||||
|
@ -157,10 +230,296 @@ impl DmfModule {
|
|||
|
||||
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 !!
|
||||
|
||||
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
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue