Patterns data

master
Ashley N. 2023-08-13 21:03:35 -04:00
parent 48f606f637
commit 5312d0fe8a
1 changed files with 196 additions and 2 deletions

View File

@ -71,6 +71,37 @@ pub struct Instrument {
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 {
platform: u8,
version: u8,
@ -103,6 +134,22 @@ fn get_i8( bytes: &mut Iter<'_, u8> ) -> Result<i8, Box<dyn Error>> {
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>> {
let took = bytes.take( 4 );
let took: Vec<u8> = took.cloned().collect();
@ -513,7 +560,83 @@ impl DmfModule {
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(
DmfModule {
@ -529,3 +652,74 @@ impl DmfModule {
}
}
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
}
}
}
}