Refactor and prepare for multiple files
parent
714b28f1aa
commit
62790d4c9c
|
@ -14,6 +14,5 @@ flate2 = "1.0.26"
|
||||||
samplerate = "0.2.4"
|
samplerate = "0.2.4"
|
||||||
hound = "3.5.0"
|
hound = "3.5.0"
|
||||||
pitch_shift = "1.0.0"
|
pitch_shift = "1.0.0"
|
||||||
uuid = { version = "1.4.1", features = [ "v4" ] }
|
|
||||||
linked_hash_set = "0.1.4"
|
linked_hash_set = "0.1.4"
|
||||||
convert_case = "0.6.0"
|
convert_case = "0.6.0"
|
|
@ -21,9 +21,11 @@ pub fn run_command() -> Result<(), Box<dyn Error>> {
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
Tools::Soundtrack { input_file, output_file, input_format: _, output_format: _, source_file_format: _, artifact_output_directory, soundtrack_label, instrument_list_label } => {
|
Tools::Soundtrack { input_file, output_file, input_format: _, output_format: _, source_file_format: _, artifact_output_directory, soundtrack_label, instrument_list_label } => {
|
||||||
let result = DmfModule::from_file( &input_file )?;
|
let result: Vec<DmfModule> = input_file.iter().map( | filename | Ok( DmfModule::from_file( &filename )? ) ).collect::<Result<Vec<DmfModule>, Box<dyn Error>>>()?;
|
||||||
|
// very temporary!
|
||||||
|
let result: &DmfModule = result.first().ok_or( "must provide input_file" )?;
|
||||||
|
|
||||||
for ( filename, data ) in result.get_artifacts( &soundtrack_label, &output_file, &artifact_output_directory, &instrument_list_label )? {
|
for ( filename, data ) in result.get_artifacts( 0, &soundtrack_label, &output_file, &artifact_output_directory, &instrument_list_label )? {
|
||||||
println!( "Creating artifact file {}{}", artifact_output_directory, filename );
|
println!( "Creating artifact file {}{}", artifact_output_directory, filename );
|
||||||
let mut file = File::create( format!( "{}{}", artifact_output_directory, filename ) )?;
|
let mut file = File::create( format!( "{}{}", artifact_output_directory, filename ) )?;
|
||||||
file.write_all( &data )?
|
file.write_all( &data )?
|
||||||
|
|
|
@ -66,9 +66,9 @@ pub enum Tools {
|
||||||
Soundtrack {
|
Soundtrack {
|
||||||
/// Input filename
|
/// Input filename
|
||||||
#[arg(short, long)]
|
#[arg(short, long)]
|
||||||
input_file: String,
|
input_file: Vec<String>,
|
||||||
|
|
||||||
/// Output filename
|
/// Output filename (if multiple input_files are provided, used as output parent directory)
|
||||||
#[arg(short, long)]
|
#[arg(short, long)]
|
||||||
output_file: String,
|
output_file: String,
|
||||||
|
|
||||||
|
|
|
@ -1,24 +1,20 @@
|
||||||
use std::{collections::HashMap, cmp::{max, min}, error::Error};
|
use std::{collections::HashMap, cmp::{max, min}, error::Error};
|
||||||
use convert_case::{Case, Casing};
|
use convert_case::{Case, Casing};
|
||||||
use samplerate::convert;
|
use samplerate::convert;
|
||||||
use uuid::Uuid;
|
use crate::reskit::{soundtrack::{formats::dmf::{DmfModule, ECHO_EWF_SAMPLE_RATE}, types::{InstrumentType, SampleFormat, Channel, PatternRow, Effect}}, utility::{print_warning, Ring}};
|
||||||
use crate::reskit::{soundtrack::{formats::dmf::{DmfModule, ECHO_EWF_SAMPLE_RATE}, types::{InstrumentType, SampleFormat, Channel, PatternRow, Effect}}, 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, ESF_SET_LOOP, ESF_GO_TO_LOOP, ESF_STOP};
|
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, ESF_SET_LOOP, ESF_GO_TO_LOOP, ESF_STOP};
|
||||||
|
|
||||||
|
|
||||||
impl EchoFormat for DmfModule {
|
impl EchoFormat for DmfModule {
|
||||||
|
|
||||||
fn get_artifacts( &self, soundtrack_label: &str, soundtrack_path: &str, artifact_path: &str, instr_list_label: &str ) -> Result<HashMap<String, Vec<u8>>, Box<dyn Error>> {
|
fn get_artifacts( &self, file_index: u32, soundtrack_label: &str, soundtrack_path: &str, artifact_path: &str, instr_list_label: &str ) -> Result<HashMap<String, Vec<u8>>, Box<dyn Error>> {
|
||||||
let mut files: HashMap<String, Vec<u8>> = HashMap::new();
|
let mut files: HashMap<String, Vec<u8>> = HashMap::new();
|
||||||
// This next list preserves order of filenames to generate the echo .asm file
|
// This next list preserves order of filenames to generate the echo .asm file
|
||||||
let mut instrument_filenames: Vec<String> = Vec::new();
|
let mut instrument_filenames: Vec<String> = Vec::new();
|
||||||
|
|
||||||
|
let mut index = 0;
|
||||||
for instrument in &self.instruments {
|
for instrument in &self.instruments {
|
||||||
match &instrument.instrument_type {
|
match &instrument.instrument_type {
|
||||||
InstrumentType::Fm2612( settings ) => {
|
InstrumentType::Fm2612( settings ) => {
|
||||||
let uuid = Uuid::new_v4().to_string();
|
|
||||||
instrument_filenames.push( format!( "{}.eif", if instrument.name.is_empty() { format!( "fm_{}", uuid ) } else { instrument.name.to_owned() } ) );
|
|
||||||
|
|
||||||
// Create feedback + algorithm byte
|
// Create feedback + algorithm byte
|
||||||
let alg_fb: u8 = ( settings.fb << 3 ) | settings.alg;
|
let alg_fb: u8 = ( settings.fb << 3 ) | settings.alg;
|
||||||
|
|
||||||
|
@ -71,12 +67,11 @@ impl EchoFormat for DmfModule {
|
||||||
eif.extend( rr_sl );
|
eif.extend( rr_sl );
|
||||||
eif.extend( ssg_eg );
|
eif.extend( ssg_eg );
|
||||||
|
|
||||||
files.insert( format!( "{}.eif", if instrument.name.is_empty() { format!( "fm_{}", uuid ) } else { instrument.name.to_owned() } ), eif );
|
let filename = format!( "file{}_ins{}_{}.eif", file_index, index, instrument.name );
|
||||||
|
instrument_filenames.push( filename.clone() );
|
||||||
|
files.insert( filename, eif );
|
||||||
},
|
},
|
||||||
InstrumentType::PsgDcsg( settings ) => {
|
InstrumentType::PsgDcsg( settings ) => {
|
||||||
let uuid = Uuid::new_v4().to_string();
|
|
||||||
instrument_filenames.push( format!( "{}.eef", if instrument.name.is_empty() { format!( "psg_{}", uuid ) } else { instrument.name.to_owned() } ) );
|
|
||||||
|
|
||||||
// Echo uses volume and arpeggio envelopes
|
// Echo uses volume and arpeggio envelopes
|
||||||
// Noise envelopes are usable but cannot be articulated in an instrument.
|
// 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.
|
// For use of the noise envelope, use ESF $0Bnn/$3Bnn and $3Ann in the stream.
|
||||||
|
@ -204,15 +199,17 @@ impl EchoFormat for DmfModule {
|
||||||
// Echo end loop command
|
// Echo end loop command
|
||||||
envelope.push( 0xFF );
|
envelope.push( 0xFF );
|
||||||
|
|
||||||
files.insert( format!( "{}.eef", if instrument.name.is_empty() { format!( "psg_{}", uuid ) } else { instrument.name.to_owned() } ), envelope );
|
let filename = format!( "file{}_ins{}_{}.eef", file_index, index, instrument.name );
|
||||||
|
instrument_filenames.push( filename.clone() );
|
||||||
|
files.insert( filename, envelope );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
index += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
index = 0;
|
||||||
for sample in &self.samples {
|
for sample in &self.samples {
|
||||||
let uuid = Uuid::new_v4().to_string();
|
|
||||||
instrument_filenames.push( format!( "{}.ewf", if sample.name.is_empty() { format!( "sample_{}", uuid ) } else { sample.name.to_owned() } ) );
|
|
||||||
|
|
||||||
// Amplify data in original sample
|
// Amplify data in original sample
|
||||||
let data: Vec<i16> = sample.data
|
let data: Vec<i16> = sample.data
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -262,7 +259,11 @@ impl EchoFormat for DmfModule {
|
||||||
// Terminate stream
|
// Terminate stream
|
||||||
data.push( 0xFF );
|
data.push( 0xFF );
|
||||||
|
|
||||||
files.insert( format!( "{}.ewf", if sample.name.is_empty() { format!( "sample_{}", uuid ) } else { sample.name.to_owned() } ), data );
|
let filename = format!( "file{}_sample{}_{}.ewf", file_index, index, sample.name );
|
||||||
|
instrument_filenames.push( filename.clone() );
|
||||||
|
files.insert( filename, data );
|
||||||
|
|
||||||
|
index += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write Echo ASM file that includes all the instruments
|
// Write Echo ASM file that includes all the instruments
|
||||||
|
|
|
@ -69,7 +69,7 @@ pub type EchoEvent = Vec<u8>;
|
||||||
|
|
||||||
pub trait EchoFormat {
|
pub trait EchoFormat {
|
||||||
|
|
||||||
fn get_artifacts( &self, soundtrack_label: &str, soundtrack_path: &str, artifact_path: &str, instrument_list_label: &str ) -> Result<HashMap<String, Vec<u8>>, Box<dyn Error>>;
|
fn get_artifacts( &self, file_index: u32, soundtrack_label: &str, soundtrack_path: &str, artifact_path: &str, instrument_list_label: &str ) -> 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>>;
|
||||||
|
|
||||||
|
|
|
@ -2,14 +2,14 @@ use std::{collections::HashMap, error::Error};
|
||||||
|
|
||||||
use linked_hash_set::LinkedHashSet;
|
use linked_hash_set::LinkedHashSet;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub struct PsgEnvelope< DataFormat > {
|
pub struct PsgEnvelope< DataFormat: PartialEq > {
|
||||||
pub envelope: Vec<DataFormat>,
|
pub envelope: Vec<DataFormat>,
|
||||||
pub loop_at: Option<usize>,
|
pub loop_at: Option<usize>,
|
||||||
pub settings: HashMap<&'static str, bool>
|
pub settings: HashMap<&'static str, bool>
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub struct PsgSettings {
|
pub struct PsgSettings {
|
||||||
pub volume: PsgEnvelope< u32 >,
|
pub volume: PsgEnvelope< u32 >,
|
||||||
pub arpeggio: PsgEnvelope< i32 >,
|
pub arpeggio: PsgEnvelope< i32 >,
|
||||||
|
@ -17,7 +17,7 @@ pub struct PsgSettings {
|
||||||
pub wavetable: PsgEnvelope< u32 >
|
pub wavetable: PsgEnvelope< u32 >
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default, PartialEq)]
|
||||||
pub struct Fm2612Operator {
|
pub struct Fm2612Operator {
|
||||||
pub am: u8,
|
pub am: u8,
|
||||||
pub ar: u8,
|
pub ar: u8,
|
||||||
|
@ -33,7 +33,7 @@ pub struct Fm2612Operator {
|
||||||
pub ssg_mode: u8
|
pub ssg_mode: u8
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub struct Fm2612Settings {
|
pub struct Fm2612Settings {
|
||||||
pub alg: u8,
|
pub alg: u8,
|
||||||
pub fb: u8,
|
pub fb: u8,
|
||||||
|
@ -42,7 +42,7 @@ pub struct Fm2612Settings {
|
||||||
pub operators: [Fm2612Operator; 4]
|
pub operators: [Fm2612Operator; 4]
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum InstrumentType {
|
pub enum InstrumentType {
|
||||||
Fm2612( Fm2612Settings ),
|
Fm2612( Fm2612Settings ),
|
||||||
PsgDcsg( PsgSettings )
|
PsgDcsg( PsgSettings )
|
||||||
|
|
Loading…
Reference in New Issue