get_instruments refactor
parent
71c95cb205
commit
b4fffa8ea9
16
src/main.rs
16
src/main.rs
|
@ -84,20 +84,8 @@ fn run() -> Result<(), Box<dyn Error>> {
|
||||||
|
|
||||||
let result = DmfModule::from_file( &input_filename )?;
|
let result = DmfModule::from_file( &input_filename )?;
|
||||||
|
|
||||||
for ( filename, data ) in result.get_eefs()? {
|
for ( filename, data ) in result.get_instruments()? {
|
||||||
println!( "Creating EEF instrument file {}", filename );
|
println!( "Creating instrument file {}", filename );
|
||||||
let mut file = File::create( filename )?;
|
|
||||||
file.write_all( &data )?
|
|
||||||
}
|
|
||||||
|
|
||||||
for ( filename, data ) in result.get_eifs()? {
|
|
||||||
println!( "Creating EIF instrument file {}", filename );
|
|
||||||
let mut file = File::create( filename )?;
|
|
||||||
file.write_all( &data )?
|
|
||||||
}
|
|
||||||
|
|
||||||
for ( filename, data ) in result.get_ewfs()? {
|
|
||||||
println!( "Creating EWF audio file {}", filename );
|
|
||||||
let mut file = File::create( filename )?;
|
let mut file = File::create( filename )?;
|
||||||
file.write_all( &data )?
|
file.write_all( &data )?
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use std::{collections::HashMap, error::Error};
|
use std::{collections::HashMap, error::Error};
|
||||||
use linked_hash_set::LinkedHashSet;
|
use linked_hash_set::LinkedHashSet;
|
||||||
|
|
||||||
use crate::reskit::{soundtrack::types::{PatternRow, Note, Channel, OctaveFrequency, Effect}, utility::print_warning};
|
use crate::reskit::{soundtrack::{types::{PatternRow, Note, Channel, OctaveFrequency, Effect}, formats::dmf::DmfModule}, utility::print_warning};
|
||||||
|
|
||||||
// https://github.com/sikthehedgehog/Echo/blob/master/doc/esf.txt
|
// https://github.com/sikthehedgehog/Echo/blob/master/doc/esf.txt
|
||||||
const ESF_NOTE_ON: u8 = 0x00;
|
const ESF_NOTE_ON: u8 = 0x00;
|
||||||
|
@ -55,13 +55,10 @@ pub type EchoEvent = Vec<u8>;
|
||||||
|
|
||||||
pub trait EchoFormat {
|
pub trait EchoFormat {
|
||||||
|
|
||||||
fn get_eefs( &self ) -> Result<HashMap<String, Vec<u8>>, Box<dyn Error>>;
|
fn get_instruments( &self ) -> Result<HashMap<String, Vec<u8>>, Box<dyn Error>>;
|
||||||
|
|
||||||
fn get_eifs( &self ) -> Result<HashMap<String, Vec<u8>>, Box<dyn Error>>;
|
|
||||||
|
|
||||||
fn get_ewfs( &self ) -> Result<HashMap<String, Vec<u8>>, Box<dyn Error>>;
|
|
||||||
|
|
||||||
fn get_esf( &self ) -> Result<Vec<u8>, Box<dyn Error>>;
|
fn get_esf( &self ) -> Result<Vec<u8>, Box<dyn Error>>;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_semitone( note: &Note ) -> Result<u8, Box<dyn Error>> {
|
fn get_semitone( note: &Note ) -> Result<u8, Box<dyn Error>> {
|
||||||
|
|
|
@ -631,202 +631,189 @@ impl DmfModule {
|
||||||
|
|
||||||
impl EchoFormat for DmfModule {
|
impl EchoFormat for DmfModule {
|
||||||
|
|
||||||
fn get_eefs( &self ) -> Result<HashMap<String, Vec<u8>>, Box<dyn Error>> {
|
fn get_instruments( &self ) -> Result<HashMap<String, Vec<u8>>, Box<dyn Error>> {
|
||||||
let mut eefs: HashMap<String, Vec<u8>> = HashMap::new();
|
let mut files: HashMap<String, Vec<u8>> = HashMap::new();
|
||||||
|
|
||||||
for instrument in &self.instruments {
|
for instrument in &self.instruments {
|
||||||
if let InstrumentType::PsgDcsg( settings ) = &instrument.instrument_type {
|
match &instrument.instrument_type {
|
||||||
// Echo uses volume and arpeggio envelopes
|
InstrumentType::Fm2612( settings ) => {
|
||||||
// Noise envelopes are usable but cannot be articulated in an instrument.
|
// Create feedback + algorithm byte
|
||||||
// For use of the noise envelope, use ESF $0Bnn/$3Bnn and $3Ann in the stream.
|
let alg_fb: u8 = ( settings.fb << 3 ) | settings.alg;
|
||||||
|
|
||||||
// comments using example: 20 vol values, 6 arp values, both repeat from the beginning
|
// 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 ];
|
||||||
|
|
||||||
// generate the initial portion (always). this is just an expansion
|
// Likewise, "operators" is laid out 1 -> 3 -> 2 -> 4
|
||||||
// of the envelopes, without loops, into two Vec<u8>'s.
|
for i in 0..4 {
|
||||||
// 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20
|
let dt: u8 = match settings.operators[ i ].dt {
|
||||||
// 01 02 03 04 05 06 -- -- -- -- -- -- -- -- -- -- -- -- -- --
|
0 => 0b000,
|
||||||
let mut volume_envelope: Vec<u8> = settings.volume.envelope.iter().map( | long | *long as u8 ).collect();
|
1 => 0b001,
|
||||||
let mut arpeggio_envelope: Vec<i8> = settings.arpeggio.envelope.iter().map( | long | *long as i8 ).collect();
|
2 => 0b010,
|
||||||
|
3 => 0b011,
|
||||||
|
-1 => 0b101,
|
||||||
|
-2 => 0b110,
|
||||||
|
-3 => 0b111,
|
||||||
|
_ => return Err( "invalid file: invalid value given for dt" )?
|
||||||
|
};
|
||||||
|
|
||||||
// now take a slice of the repeatable portion of the smaller array,
|
// https://plutiedev.com/ym2612-registers
|
||||||
// and use it to expand the smaller array to the same size as the
|
// https://github.com/sikthehedgehog/Echo/blob/master/doc/eif.txt
|
||||||
// larger array. if there is no repeatable portion, take a one-element
|
mult_dt[ i ] = ( dt << 4 ) | settings.operators[ i ].mult;
|
||||||
// slice of the last element in the array.
|
tl[ i ] = settings.operators[ i ].tl;
|
||||||
// 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20
|
ar_rs[ i ] = ( settings.operators[ i ].rs << 6 ) | settings.operators[ i ].ar;
|
||||||
// 01 02 03 04 05 06 01 02 03 04 05 06 01 02 03 04 05 06 01 02
|
dr_am[ i ] = ( settings.operators[ i ].am << 7 ) | settings.operators[ i ].dr;
|
||||||
let mut volume_repeat_pattern: Ring<u8> = Ring::create(
|
sr[ i ] = settings.operators[ i ].d2r; // "Sometimes also called 'second decay rate' (D2R)."
|
||||||
if let Some( loop_at ) = settings.volume.loop_at {
|
rr_sl[ i ] = ( settings.operators[ i ].sl << 4 ) | settings.operators[ i ].rr;
|
||||||
Vec::from( &volume_envelope[ loop_at.. ] )
|
|
||||||
} else {
|
|
||||||
vec![ volume_envelope[ volume_envelope.len() - 1 ] ]
|
|
||||||
},
|
|
||||||
None
|
|
||||||
);
|
|
||||||
let mut arpeggio_repeat_pattern: Ring<i8> = Ring::create(
|
|
||||||
if let Some( loop_at ) = settings.arpeggio.loop_at {
|
|
||||||
Vec::from( &arpeggio_envelope[ loop_at.. ] )
|
|
||||||
} else {
|
|
||||||
vec![ arpeggio_envelope[ arpeggio_envelope.len() - 1 ] ]
|
|
||||||
},
|
|
||||||
None
|
|
||||||
);
|
|
||||||
|
|
||||||
if volume_envelope.len() < arpeggio_envelope.len() {
|
if settings.operators[ i ].ssg_mode > 0 {
|
||||||
let difference = arpeggio_envelope.len() - volume_envelope.len();
|
print_warning( &format!( "SSG-EG mode set on instrument {}, operator {}. this operator may not work on clone hardware or certain emulators", instrument.name, i ) );
|
||||||
for _ in 0..difference {
|
}
|
||||||
volume_envelope.push(
|
|
||||||
volume_repeat_pattern.next().expect( "fatal: internal error (volume_repeat_pattern)" )
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else if arpeggio_envelope.len() < volume_envelope.len() {
|
|
||||||
let difference = volume_envelope.len() - arpeggio_envelope.len();
|
|
||||||
for _ in 0..difference {
|
|
||||||
arpeggio_envelope.push(
|
|
||||||
arpeggio_repeat_pattern.next().expect( "fatal: internal error (arpeggio_repeat_pattern)" )
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let interval_size = max( volume_repeat_pattern.len(), arpeggio_repeat_pattern.len() );
|
ssg_eg[ i ] = settings.operators[ i ].ssg_mode;
|
||||||
|
|
||||||
// now, you generate the repeating portion using the two repeat_pattern iterators.
|
|
||||||
// each segment at a time is generated by the size of the larger array.
|
|
||||||
// generate it until the first repeat pattern is regenerated.
|
|
||||||
// 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 .. (volume repeats from beginning)
|
|
||||||
// 03 04 05 06 01 02 03 04 05 06 01 02 03 04 05 06 01 02 03 04 .. (arpeggio repeats up from where it left off)
|
|
||||||
|
|
||||||
// 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 ..
|
|
||||||
// 05 06 01 02 03 04 05 06 01 02 03 04 05 06 01 02 03 04 05 06 ..
|
|
||||||
|
|
||||||
// 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 ..
|
|
||||||
// 01 02 03 04 05 06 01 02 03 04 05 06 01 02 03 04 05 06 01 02 ..
|
|
||||||
let mut volume_repeat: Vec<u8> = Vec::new();
|
|
||||||
let mut arpeggio_repeat: Vec<i8> = Vec::new();
|
|
||||||
|
|
||||||
let mut initial_volume_repeat: Vec<u8> = Vec::new();
|
|
||||||
let mut initial_arpeggio_repeat: Vec<i8> = Vec::new();
|
|
||||||
for _ in 0..interval_size {
|
|
||||||
initial_volume_repeat.push( volume_repeat_pattern.next().expect( "fatal: internal error (volume_repeat_pattern)" ) );
|
|
||||||
initial_arpeggio_repeat.push( arpeggio_repeat_pattern.next().expect( "fatal: internal error (arpeggio_repeat_pattern)" ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
volume_repeat.extend( &initial_volume_repeat );
|
|
||||||
arpeggio_repeat.extend( &initial_arpeggio_repeat );
|
|
||||||
|
|
||||||
loop {
|
|
||||||
// Guard against OOM
|
|
||||||
if volume_repeat.len() > 65535 {
|
|
||||||
return Err( "eef error: psg instrument repeat period too long (try modifying repeating envelopes to have evenly-divisible parameters)" )?
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut volume_repeat_period: Vec<u8> = Vec::new();
|
let mut eif: Vec<u8> = Vec::new();
|
||||||
let mut arpeggio_repeat_period: Vec<i8> = 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 );
|
||||||
|
|
||||||
|
files.insert( format!( "{}.eif", if instrument.name.is_empty() { Uuid::new_v4().to_string() } else { instrument.name.to_owned() } ), eif );
|
||||||
|
},
|
||||||
|
InstrumentType::PsgDcsg( settings ) => {
|
||||||
|
// Echo uses volume and arpeggio envelopes
|
||||||
|
// Noise envelopes are usable but cannot be articulated in an instrument.
|
||||||
|
// For use of the noise envelope, use ESF $0Bnn/$3Bnn and $3Ann in the stream.
|
||||||
|
|
||||||
|
// comments using example: 20 vol values, 6 arp values, both repeat from the beginning
|
||||||
|
|
||||||
|
// generate the initial portion (always). this is just an expansion
|
||||||
|
// of the envelopes, without loops, into two Vec<u8>'s.
|
||||||
|
// 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20
|
||||||
|
// 01 02 03 04 05 06 -- -- -- -- -- -- -- -- -- -- -- -- -- --
|
||||||
|
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();
|
||||||
|
|
||||||
|
// 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
|
||||||
|
// slice of the last element in the array.
|
||||||
|
// 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20
|
||||||
|
// 01 02 03 04 05 06 01 02 03 04 05 06 01 02 03 04 05 06 01 02
|
||||||
|
let mut volume_repeat_pattern: Ring<u8> = Ring::create(
|
||||||
|
if let Some( loop_at ) = settings.volume.loop_at {
|
||||||
|
Vec::from( &volume_envelope[ loop_at.. ] )
|
||||||
|
} else {
|
||||||
|
vec![ volume_envelope[ volume_envelope.len() - 1 ] ]
|
||||||
|
},
|
||||||
|
None
|
||||||
|
);
|
||||||
|
let mut arpeggio_repeat_pattern: Ring<i8> = Ring::create(
|
||||||
|
if let Some( loop_at ) = settings.arpeggio.loop_at {
|
||||||
|
Vec::from( &arpeggio_envelope[ loop_at.. ] )
|
||||||
|
} else {
|
||||||
|
vec![ arpeggio_envelope[ arpeggio_envelope.len() - 1 ] ]
|
||||||
|
},
|
||||||
|
None
|
||||||
|
);
|
||||||
|
|
||||||
|
if volume_envelope.len() < arpeggio_envelope.len() {
|
||||||
|
let difference = arpeggio_envelope.len() - volume_envelope.len();
|
||||||
|
for _ in 0..difference {
|
||||||
|
volume_envelope.push(
|
||||||
|
volume_repeat_pattern.next().expect( "fatal: internal error (volume_repeat_pattern)" )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else if arpeggio_envelope.len() < volume_envelope.len() {
|
||||||
|
let difference = volume_envelope.len() - arpeggio_envelope.len();
|
||||||
|
for _ in 0..difference {
|
||||||
|
arpeggio_envelope.push(
|
||||||
|
arpeggio_repeat_pattern.next().expect( "fatal: internal error (arpeggio_repeat_pattern)" )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let interval_size = max( volume_repeat_pattern.len(), arpeggio_repeat_pattern.len() );
|
||||||
|
|
||||||
|
// now, you generate the repeating portion using the two repeat_pattern iterators.
|
||||||
|
// each segment at a time is generated by the size of the larger array.
|
||||||
|
// generate it until the first repeat pattern is regenerated.
|
||||||
|
// 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 .. (volume repeats from beginning)
|
||||||
|
// 03 04 05 06 01 02 03 04 05 06 01 02 03 04 05 06 01 02 03 04 .. (arpeggio repeats up from where it left off)
|
||||||
|
|
||||||
|
// 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 ..
|
||||||
|
// 05 06 01 02 03 04 05 06 01 02 03 04 05 06 01 02 03 04 05 06 ..
|
||||||
|
|
||||||
|
// 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 ..
|
||||||
|
// 01 02 03 04 05 06 01 02 03 04 05 06 01 02 03 04 05 06 01 02 ..
|
||||||
|
let mut volume_repeat: Vec<u8> = Vec::new();
|
||||||
|
let mut arpeggio_repeat: Vec<i8> = Vec::new();
|
||||||
|
|
||||||
|
let mut initial_volume_repeat: Vec<u8> = Vec::new();
|
||||||
|
let mut initial_arpeggio_repeat: Vec<i8> = Vec::new();
|
||||||
for _ in 0..interval_size {
|
for _ in 0..interval_size {
|
||||||
volume_repeat_period.push( volume_repeat_pattern.next().expect( "fatal: internal error (volume_repeat_pattern)" ) );
|
initial_volume_repeat.push( volume_repeat_pattern.next().expect( "fatal: internal error (volume_repeat_pattern)" ) );
|
||||||
arpeggio_repeat_period.push( arpeggio_repeat_pattern.next().expect( "fatal: internal error (arpeggio_repeat_pattern)" ) );
|
initial_arpeggio_repeat.push( arpeggio_repeat_pattern.next().expect( "fatal: internal error (arpeggio_repeat_pattern)" ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
// End loop once the pattern begins repeating
|
volume_repeat.extend( &initial_volume_repeat );
|
||||||
if initial_volume_repeat == volume_repeat_period && initial_arpeggio_repeat == arpeggio_repeat_period {
|
arpeggio_repeat.extend( &initial_arpeggio_repeat );
|
||||||
break;
|
|
||||||
} else {
|
loop {
|
||||||
// If it doesn't repeat, append and generate another period
|
// Guard against OOM
|
||||||
volume_repeat.append( &mut volume_repeat_period );
|
if volume_repeat.len() > 65535 {
|
||||||
arpeggio_repeat.append( &mut arpeggio_repeat_period );
|
return Err( "eef error: psg instrument repeat period too long (try modifying repeating envelopes to have evenly-divisible parameters)" )?
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut volume_repeat_period: Vec<u8> = Vec::new();
|
||||||
|
let mut arpeggio_repeat_period: Vec<i8> = Vec::new();
|
||||||
|
for _ in 0..interval_size {
|
||||||
|
volume_repeat_period.push( volume_repeat_pattern.next().expect( "fatal: internal error (volume_repeat_pattern)" ) );
|
||||||
|
arpeggio_repeat_period.push( arpeggio_repeat_pattern.next().expect( "fatal: internal error (arpeggio_repeat_pattern)" ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
// End loop once the pattern begins repeating
|
||||||
|
if initial_volume_repeat == volume_repeat_period && initial_arpeggio_repeat == arpeggio_repeat_period {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
// If it doesn't repeat, append and generate another period
|
||||||
|
volume_repeat.append( &mut volume_repeat_period );
|
||||||
|
arpeggio_repeat.append( &mut arpeggio_repeat_period );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Now generate the Echo EEF envelope from volume_envelope/volume_repeat + arpeggio_envelope/arpeggio_repeat
|
||||||
|
let mut envelope: Vec<u8> = vec![ 0x00 ];
|
||||||
|
for i in 0..volume_envelope.len() {
|
||||||
|
envelope.push( get_eef_volume( volume_envelope[ i ] )? | get_eef_shift( arpeggio_envelope[ i ] )? );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Echo begin loop command
|
||||||
|
envelope.push( 0xFE );
|
||||||
|
|
||||||
|
for i in 0..volume_repeat.len() {
|
||||||
|
envelope.push( get_eef_volume( volume_repeat[ i ] )? | get_eef_shift( arpeggio_repeat[ i ] )? );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Echo end loop command
|
||||||
|
envelope.push( 0xFF );
|
||||||
|
|
||||||
|
files.insert( format!( "{}.eef", if instrument.name.is_empty() { Uuid::new_v4().to_string() } else { instrument.name.to_owned() } ), envelope );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now generate the Echo EEF envelope from volume_envelope/volume_repeat + arpeggio_envelope/arpeggio_repeat
|
|
||||||
let mut envelope: Vec<u8> = vec![ 0x00 ];
|
|
||||||
for i in 0..volume_envelope.len() {
|
|
||||||
envelope.push( get_eef_volume( volume_envelope[ i ] )? | get_eef_shift( arpeggio_envelope[ i ] )? );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Echo begin loop command
|
|
||||||
envelope.push( 0xFE );
|
|
||||||
|
|
||||||
for i in 0..volume_repeat.len() {
|
|
||||||
envelope.push( get_eef_volume( volume_repeat[ i ] )? | get_eef_shift( arpeggio_repeat[ i ] )? );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Echo end loop command
|
|
||||||
envelope.push( 0xFF );
|
|
||||||
|
|
||||||
eefs.insert( format!( "{}.eef", if instrument.name.is_empty() { Uuid::new_v4().to_string() } else { instrument.name.to_owned() } ), envelope );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok( eefs )
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_eifs( &self ) -> Result<HashMap<String, Vec<u8>>, Box<dyn Error>> {
|
|
||||||
let mut eifs: HashMap<String, Vec<u8>> = HashMap::new();
|
|
||||||
|
|
||||||
for instrument in &self.instruments {
|
|
||||||
if let InstrumentType::Fm2612( settings ) = &instrument.instrument_type {
|
|
||||||
// Create feedback + algorithm byte
|
|
||||||
let alg_fb: u8 = ( settings.fb << 3 ) | settings.alg;
|
|
||||||
|
|
||||||
// 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<u8> = 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", if instrument.name.is_empty() { Uuid::new_v4().to_string() } else { instrument.name.to_owned() } ), eif );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok( eifs )
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_ewfs( &self ) -> Result<HashMap<String, Vec<u8>>, Box<dyn Error>> {
|
|
||||||
let mut ewfs: HashMap<String, Vec<u8>> = HashMap::new();
|
|
||||||
|
|
||||||
for sample in &self.samples {
|
for sample in &self.samples {
|
||||||
// Amplify data in original sample
|
// Amplify data in original sample
|
||||||
let data: Vec<i16> = sample.data
|
let data: Vec<i16> = sample.data
|
||||||
|
@ -877,10 +864,10 @@ impl EchoFormat for DmfModule {
|
||||||
// Terminate stream
|
// Terminate stream
|
||||||
data.push( 0xFF );
|
data.push( 0xFF );
|
||||||
|
|
||||||
ewfs.insert( format!( "{}.ewf", if sample.name.is_empty() { Uuid::new_v4().to_string() } else { sample.name.to_owned() } ), data );
|
files.insert( format!( "{}.ewf", if sample.name.is_empty() { Uuid::new_v4().to_string() } else { sample.name.to_owned() } ), data );
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok( ewfs )
|
Ok( files )
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_esf( &self ) -> Result<Vec<u8>, Box<dyn Error>> {
|
fn get_esf( &self ) -> Result<Vec<u8>, Box<dyn Error>> {
|
||||||
|
|
Loading…
Reference in New Issue