diff --git a/src/main.rs b/src/main.rs index 64fd307..9244676 100644 --- a/src/main.rs +++ b/src/main.rs @@ -89,6 +89,13 @@ fn run() -> Result<(), Box> { file.write_all( &data )? } + let eif_files = result.get_eifs()?; + for ( filename, data ) in eif_files { + println!( "Creating EIF instrument file {}", filename ); + let mut file = File::create( filename )?; + file.write_all( &data )? + } + // TODO !! Ok( () ) diff --git a/src/reskit/soundtrack/formats/dmf.rs b/src/reskit/soundtrack/formats/dmf.rs index a61537a..4de4038 100644 --- a/src/reskit/soundtrack/formats/dmf.rs +++ b/src/reskit/soundtrack/formats/dmf.rs @@ -1,6 +1,6 @@ use std::{error::Error, fs::File, io::Read, convert::TryInto, collections::HashMap, cmp::{min, max}}; use flate2::read::ZlibDecoder; -use crate::reskit::{utility::{get_string, get_u8, skip, get_u32, get_i8, get_i32, get_u16, get_i16, Ring}, soundtrack::{types::{SampleRate, SampleFormat, PsgEnvelope, Note, Sample, PsgSettings}, engines::echo::EchoFormat}}; +use crate::reskit::{utility::{get_string, get_u8, skip, get_u32, get_i8, get_i32, get_u16, get_i16, Ring, print_warning}, soundtrack::{types::{SampleRate, SampleFormat, PsgEnvelope, Note, Sample, PsgSettings}, engines::echo::EchoFormat}}; const DMF_MAGIC_NUMBER: &'static str = ".DelekDefleMask."; const DMF_SUPPORTED_VERSION: u8 = 27; @@ -377,35 +377,6 @@ impl DmfModule { } // 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() )?; @@ -420,18 +391,47 @@ impl DmfModule { 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 ); + println!( "Op 3 AM:\t{}", operators[ 1 ].am ); + println!( "Op 3 AR:\t{}", operators[ 1 ].ar ); + println!( "Op 3 DR:\t{}", operators[ 1 ].dr ); + println!( "Op 3 MULT:\t{}", operators[ 1 ].mult ); + println!( "Op 3 RR:\t{}", operators[ 1 ].rr ); + println!( "Op 3 SL:\t{}", operators[ 1 ].sl ); + println!( "Op 3 TL:\t{}", operators[ 1 ].tl ); + println!( "Op 3 DT2:\t{}", operators[ 1 ].dt2 ); + println!( "Op 3 RS:\t{}", operators[ 1 ].rs ); + println!( "Op 3 DT:\t{}", operators[ 1 ].dt ); + println!( "Op 3 D2R:\t{}", operators[ 1 ].d2r ); + println!( "Op 3 SSG_MODE:\t{}\n", operators[ 1 ].ssg_mode ); + } + + // Operator 2 + { + 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 2 AM:\t{}", operators[ 2 ].am ); + println!( "Op 2 AR:\t{}", operators[ 2 ].ar ); + println!( "Op 2 DR:\t{}", operators[ 2 ].dr ); + println!( "Op 2 MULT:\t{}", operators[ 2 ].mult ); + println!( "Op 2 RR:\t{}", operators[ 2 ].rr ); + println!( "Op 2 SL:\t{}", operators[ 2 ].sl ); + println!( "Op 2 TL:\t{}", operators[ 2 ].tl ); + println!( "Op 2 DT2:\t{}", operators[ 2 ].dt2 ); + println!( "Op 2 RS:\t{}", operators[ 2 ].rs ); + println!( "Op 2 DT:\t{}", operators[ 2 ].dt ); + println!( "Op 2 D2R:\t{}", operators[ 2 ].d2r ); + println!( "Op 2 SSG_MODE:\t{}\n", operators[ 2 ].ssg_mode ); } // Operator 4 @@ -747,7 +747,56 @@ impl EchoFormat for DmfModule { // Create feedback + algorithm byte let alg_fb: u8 = ( settings.fb << 3 ) | settings.alg; - todo!() + // The operators are laid out as FmOperator objects in order 1 -> 3 -> 2 -> 4 + // EIF instrument layout below + let mut mult_dt: [u8; 4] = [ 0x00, 0x00, 0x00, 0x00 ]; + let mut tl: [u8; 4] = [ 0x00, 0x00, 0x00, 0x00 ]; + let mut ar_rs: [u8; 4] = [ 0x00, 0x00, 0x00, 0x00 ]; + let mut dr_am: [u8; 4] = [ 0x00, 0x00, 0x00, 0x00 ]; + let mut sr: [u8; 4] = [ 0x00, 0x00, 0x00, 0x00 ]; + let mut rr_sl: [u8; 4] = [ 0x00, 0x00, 0x00, 0x00 ]; + let mut ssg_eg: [u8; 4] = [ 0x00, 0x00, 0x00, 0x00 ]; + + // Likewise, "operators" is laid out 1 -> 3 -> 2 -> 4 + for i in 0..4 { + let dt: u8 = match settings.operators[ i ].dt { + 0 => 0b000, + 1 => 0b001, + 2 => 0b010, + 3 => 0b011, + -1 => 0b101, + -2 => 0b110, + -3 => 0b111, + _ => return Err( "invalid file: invalid value given for dt" )? + }; + + // https://plutiedev.com/ym2612-registers + // https://github.com/sikthehedgehog/Echo/blob/master/doc/eif.txt + mult_dt[ i ] = ( dt << 4 ) | settings.operators[ i ].mult; + tl[ i ] = settings.operators[ i ].tl; + ar_rs[ i ] = ( settings.operators[ i ].rs << 6 ) | settings.operators[ i ].ar; + dr_am[ i ] = ( settings.operators[ i ].am << 7 ) | settings.operators[ i ].dr; + sr[ i ] = settings.operators[ i ].d2r; // "Sometimes also called 'second decay rate' (D2R)." + rr_sl[ i ] = ( settings.operators[ i ].sl << 4 ) | settings.operators[ i ].rr; + + if settings.operators[ i ].ssg_mode > 0 { + print_warning( &format!( "SSG-EG mode set on instrument {}, operator {}. this operator may not work on clone hardware or certain emulators", instrument.name, i ) ); + } + + ssg_eg[ i ] = settings.operators[ i ].ssg_mode; + } + + let mut eif: Vec = Vec::new(); + eif.push( alg_fb ); + eif.extend( mult_dt ); + eif.extend( tl ); + eif.extend( ar_rs ); + eif.extend( dr_am ); + eif.extend( sr ); + eif.extend( rr_sl ); + eif.extend( ssg_eg ); + + eifs.insert( format!( "{}.eif", instrument.name), eif ); } } diff --git a/src/reskit/utility.rs b/src/reskit/utility.rs index 8e108be..3d0ce96 100644 --- a/src/reskit/utility.rs +++ b/src/reskit/utility.rs @@ -45,6 +45,10 @@ pub fn print_good( message: &str ) { green!( "success: " ); println!( "{}", message ); } +pub fn print_warning( message: &str ) { + yellow!( "warning: " ); println!( "{}", message ); +} + pub fn get_string( bytes: &mut Iter<'_, u8>, take: usize ) -> Result> { let took = bytes.take( take ); let took: Vec = took.cloned().collect();