Patterns data
parent
48f606f637
commit
5312d0fe8a
|
@ -71,6 +71,37 @@ pub struct Instrument {
|
||||||
instrument_type: InstrumentType
|
instrument_type: InstrumentType
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Note {
|
||||||
|
NoteOff,
|
||||||
|
CSharp( u16 ),
|
||||||
|
D( u16 ),
|
||||||
|
DSharp( u16 ),
|
||||||
|
E( u16 ),
|
||||||
|
F( u16 ),
|
||||||
|
FSharp( u16 ),
|
||||||
|
G( u16 ),
|
||||||
|
GSharp( u16 ),
|
||||||
|
A( u16 ),
|
||||||
|
ASharp( u16 ),
|
||||||
|
B( u16 ),
|
||||||
|
C( u16 )
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Effect {
|
||||||
|
effect_code: i16,
|
||||||
|
effect_value: Option<i16>
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct PatternRow {
|
||||||
|
note: Option<Note>,
|
||||||
|
volume: Option<i16>,
|
||||||
|
effects: Vec<Effect>,
|
||||||
|
instrument_index: Option<u16>
|
||||||
|
}
|
||||||
|
|
||||||
pub struct DmfModule {
|
pub struct DmfModule {
|
||||||
platform: u8,
|
platform: u8,
|
||||||
version: u8,
|
version: u8,
|
||||||
|
@ -103,6 +134,22 @@ fn get_i8( bytes: &mut Iter<'_, u8> ) -> Result<i8, Box<dyn Error>> {
|
||||||
Ok( took as i8 )
|
Ok( took as i8 )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_u16( bytes: &mut Iter<'_, u8> ) -> Result<u16, Box<dyn Error>> {
|
||||||
|
let took = bytes.take( 2 );
|
||||||
|
let took: Vec<u8> = took.cloned().collect();
|
||||||
|
let took = u16::from_le_bytes( took[0..2].try_into()? );
|
||||||
|
|
||||||
|
Ok( took )
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_i16( bytes: &mut Iter<'_, u8> ) -> Result<i16, Box<dyn Error>> {
|
||||||
|
let took = bytes.take( 2 );
|
||||||
|
let took: Vec<u8> = took.cloned().collect();
|
||||||
|
let took = i16::from_le_bytes( took[0..2].try_into()? );
|
||||||
|
|
||||||
|
Ok( took )
|
||||||
|
}
|
||||||
|
|
||||||
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();
|
||||||
|
@ -513,7 +560,83 @@ impl DmfModule {
|
||||||
instruments.push( Instrument { name, instrument_type } );
|
instruments.push( Instrument { name, instrument_type } );
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO !!
|
// Wavetables are not used in fm synthesis, this should validate as 0 or error
|
||||||
|
let wavetable_count = get_u8( bytes.by_ref() )?;
|
||||||
|
if wavetable_count > 0 {
|
||||||
|
return Err( "invalid file: wavetables should be zero for system type Sega Megadrive" )?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// (channel, patterns)
|
||||||
|
let mut channel_patterns: Vec<Vec<PatternRow>> = Vec::new();
|
||||||
|
for _ in 0..system_total_channels {
|
||||||
|
let mut channel_rows: Vec<PatternRow> = Vec::new();
|
||||||
|
let num_effects = get_u8( bytes.by_ref() )?;
|
||||||
|
|
||||||
|
for _ in 0..patterns_count {
|
||||||
|
for _ in 0..rows_per_pattern {
|
||||||
|
let note = get_u16( bytes.by_ref() )?;
|
||||||
|
let octave = get_u16( bytes.by_ref() )?;
|
||||||
|
|
||||||
|
let note: Option<Note> = if note == 0 && octave == 0 {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(
|
||||||
|
match note {
|
||||||
|
100 => Note::NoteOff,
|
||||||
|
1 => Note::CSharp( octave ),
|
||||||
|
2 => Note::D( octave ),
|
||||||
|
3 => Note::DSharp( octave ),
|
||||||
|
4 => Note::E( octave ),
|
||||||
|
5 => Note::F( octave ),
|
||||||
|
6 => Note::FSharp( octave ),
|
||||||
|
7 => Note::G( octave ),
|
||||||
|
8 => Note::GSharp( octave ),
|
||||||
|
9 => Note::A( octave ),
|
||||||
|
10 => Note::ASharp( octave ),
|
||||||
|
11 => Note::B( octave ),
|
||||||
|
12 => Note::C( octave ),
|
||||||
|
_ => return Err( format!( "invalid file: invalid note id {}", note ) )?
|
||||||
|
}
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
let volume = get_i16( bytes.by_ref() )?;
|
||||||
|
let volume: Option<i16> = if volume == -1 {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some( volume )
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut effects: Vec<Effect> = Vec::new();
|
||||||
|
for _ in 0..num_effects {
|
||||||
|
let effect_code = get_i16( bytes.by_ref() )?;
|
||||||
|
let effect_value = get_i16( bytes.by_ref() )?;
|
||||||
|
|
||||||
|
if effect_code != -1 {
|
||||||
|
effects.push(
|
||||||
|
Effect{
|
||||||
|
effect_code,
|
||||||
|
effect_value: if effect_value != -1 { Some( effect_code ) } else { None }
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let instrument_index = get_i16( bytes.by_ref() )?;
|
||||||
|
let instrument_index: Option<u16> = if instrument_index != -1 {
|
||||||
|
Some( instrument_index.try_into()? )
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
channel_rows.push( PatternRow { note, volume, effects, instrument_index } );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
channel_patterns.push( channel_rows );
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: PCM Samples !!
|
||||||
|
|
||||||
Ok(
|
Ok(
|
||||||
DmfModule {
|
DmfModule {
|
||||||
|
@ -528,4 +651,75 @@ impl DmfModule {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl Note {
|
||||||
|
|
||||||
|
pub fn get_freq( &self ) -> Option<f32> {
|
||||||
|
match self {
|
||||||
|
Note::NoteOff => None,
|
||||||
|
Note::CSharp( octave ) => match octave {
|
||||||
|
0 => Some( 17.32 ), 1 => Some( 34.65 ), 2 => Some( 69.30 ), 3 => Some( 138.59 ),
|
||||||
|
4 => Some( 277.18 ), 5 => Some( 554.37 ), 6 => Some( 1108.73 ), 7 => Some( 2217.46 ),
|
||||||
|
_ => None
|
||||||
|
},
|
||||||
|
Note::D( octave ) => match octave {
|
||||||
|
0 => Some( 18.35 ), 1 => Some( 36.71 ), 2 => Some( 73.42 ), 3 => Some( 146.83 ),
|
||||||
|
4 => Some( 293.66 ), 5 => Some( 587.33 ), 6 => Some( 1174.66 ), 7 => Some( 2349.32 ),
|
||||||
|
_ => None
|
||||||
|
},
|
||||||
|
Note::DSharp( octave ) => match octave {
|
||||||
|
0 => Some( 19.45 ), 1 => Some( 38.89 ), 2 => Some( 77.78 ), 3 => Some( 155.56 ),
|
||||||
|
4 => Some( 311.13 ), 5 => Some( 622.25 ), 6 => Some( 1244.51 ), 7 => Some( 2489.02 ),
|
||||||
|
_ => None
|
||||||
|
},
|
||||||
|
Note::E( octave ) => match octave {
|
||||||
|
0 => Some( 20.60 ), 1 => Some( 41.20 ), 2 => Some( 82.41 ), 3 => Some( 164.81 ),
|
||||||
|
4 => Some( 329.63 ), 5 => Some( 659.25 ), 6 => Some( 1318.51 ), 7 => Some( 2637.02 ),
|
||||||
|
_ => None
|
||||||
|
},
|
||||||
|
Note::F( octave ) => match octave {
|
||||||
|
0 => Some( 21.83 ), 1 => Some( 43.65 ), 2 => Some( 87.31 ), 3 => Some( 174.61 ),
|
||||||
|
4 => Some( 349.23 ), 5 => Some( 698.46 ), 6 => Some( 1396.91 ), 7 => Some( 2793.83 ),
|
||||||
|
_ => None
|
||||||
|
},
|
||||||
|
Note::FSharp( octave ) => match octave {
|
||||||
|
0 => Some( 23.12 ), 1 => Some( 46.25 ), 2 => Some( 92.50 ), 3 => Some( 185.00 ),
|
||||||
|
4 => Some( 369.99 ), 5 => Some( 739.99 ), 6 => Some( 1479.98 ), 7 => Some( 2959.96 ),
|
||||||
|
_ => None
|
||||||
|
},
|
||||||
|
Note::G( octave ) => match octave {
|
||||||
|
0 => Some( 24.50 ), 1 => Some( 49.00 ), 2 => Some( 98.00 ), 3 => Some( 196.00 ),
|
||||||
|
4 => Some( 392.00 ), 5 => Some( 783.99 ), 6 => Some( 1567.98 ), 7 => Some( 3135.96 ),
|
||||||
|
_ => None
|
||||||
|
},
|
||||||
|
Note::GSharp( octave ) => match octave {
|
||||||
|
0 => Some( 25.96 ), 1 => Some( 51.91 ), 2 => Some( 103.83 ), 3 => Some( 207.65 ),
|
||||||
|
4 => Some( 415.30 ), 5 => Some( 830.61 ), 6 => Some( 1661.22 ), 7 => Some( 3322.44 ),
|
||||||
|
_ => None
|
||||||
|
},
|
||||||
|
Note::A( octave ) => match octave {
|
||||||
|
0 => Some( 27.50 ), 1 => Some( 55.00 ), 2 => Some( 110.00 ), 3 => Some( 220.00 ),
|
||||||
|
4 => Some( 440.00 ), 5 => Some( 880.00 ), 6 => Some( 1760.00 ), 7 => Some( 3520.00 ),
|
||||||
|
_ => None
|
||||||
|
},
|
||||||
|
Note::ASharp( octave ) => match octave {
|
||||||
|
0 => Some( 29.14 ), 1 => Some( 58.27 ), 2 => Some( 116.54 ), 3 => Some( 233.08 ),
|
||||||
|
4 => Some( 466.16 ), 5 => Some( 932.33 ), 6 => Some( 1864.66 ), 7 => Some( 3729.31 ),
|
||||||
|
_ => None
|
||||||
|
},
|
||||||
|
Note::B( octave ) => match octave {
|
||||||
|
0 => Some( 30.87 ), 1 => Some( 61.74 ), 2 => Some( 123.47 ), 3 => Some( 246.94 ),
|
||||||
|
4 => Some( 493.88 ), 5 => Some( 987.77 ), 6 => Some( 1975.53 ), 7 => Some( 3951.07 ),
|
||||||
|
_ => None
|
||||||
|
},
|
||||||
|
Note::C( octave ) => match octave {
|
||||||
|
0 => Some( 16.35 ), 1 => Some( 32.70 ), 2 => Some( 65.41 ), 3 => Some( 130.81 ),
|
||||||
|
4 => Some( 261.63 ), 5 => Some( 523.25 ), 6 => Some( 1046.50 ), 7 => Some( 2093.00 ),
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue