diff options
author | Chris Xiong <chirs241097@gmail.com> | 2022-11-25 23:34:51 -0500 |
---|---|---|
committer | Chris Xiong <chirs241097@gmail.com> | 2022-11-25 23:34:51 -0500 |
commit | f8cf52fa4b2bbaff5627fa397a26589070084d3e (patch) | |
tree | 6ffc67fbba825eed811409732ce8e6cbda0dc38f /src/midifile.rs | |
parent | 736033237b41f91bcc093c06780e47c4ad5febaa (diff) | |
download | it2midi-f8cf52fa4b2bbaff5627fa397a26589070084d3e.tar.xz |
Actually produce some valid midi output.
Major restructure in the IT player: No more custom trait objects,
let's just use closures instead...
Basic note handling.
Fixes to the midi file modules so the output is now valid.
Other fixes to appease the Rust Gods.
Current converter handles no IT effects (except timing effects like
Axx, Bxx, Cxx, SBx and SEx, as those are handled as a part of
the player). But this is a start.
Diffstat (limited to 'src/midifile.rs')
-rw-r--r-- | src/midifile.rs | 27 |
1 files changed, 16 insertions, 11 deletions
diff --git a/src/midifile.rs b/src/midifile.rs index 71a861c..219a931 100644 --- a/src/midifile.rs +++ b/src/midifile.rs @@ -10,6 +10,7 @@ pub struct RawMidiEvent data: Vec<u8> } +#[derive(Clone)] pub enum MidiEvent { NoteOn{ch: u8, key: u8, vel: u8}, @@ -26,6 +27,7 @@ pub enum MidiEvent MetaEndOfTrack } +#[derive(Clone)] pub struct TimedMidiEvent { pub t: u32, @@ -39,7 +41,7 @@ impl From<&MidiEvent> for RawMidiEvent match e { MidiEvent::NoteOff{ch, key, vel} - if *vel == 0x40 => RawMidiEvent{ty: 0x90 | ch, p1: *key, p2: 0, data:vec![]}, + if *vel == 0x40 => RawMidiEvent{ty: 0x90 | ch, p1: *key, p2: 0, data: vec![]}, MidiEvent::NoteOff{ch, key, vel} => RawMidiEvent{ty: 0x80 | ch, p1: *key, p2: *vel, data: vec![]}, MidiEvent::NoteOn {ch, key, vel} => RawMidiEvent{ty: 0x90 | ch, p1: *key, p2: *vel, data: vec![]}, MidiEvent::KeyAfterTouch{ch, key, val} => RawMidiEvent{ty: 0xa0 | ch, p1: *key, p2: *val, data: vec![]}, @@ -64,12 +66,12 @@ impl From<&MidiEvent> for RawMidiEvent RawMidiEvent{ty: 0xff, p1: 0x03, p2: s.len() as u8, data: Vec::from(sb)} } MidiEvent::MetaEndOfTrack => - RawMidiEvent{ty: 0xff, p1: 0x2f, p2: 0xff, data: vec![]} + RawMidiEvent{ty: 0xff, p1: 0x2f, p2: 0, data: vec![]} } } } -type MidiTrack = Vec<TimedMidiEvent>; +pub type MidiTrack = Vec<TimedMidiEvent>; pub struct MidiFile { @@ -77,19 +79,19 @@ pub struct MidiFile pub tracks: Vec<MidiTrack> } -fn write_u16be(f: &mut File, v: u16) -> io::Result<()> +fn write_u16be<W>(f: &mut W, v: u16) -> io::Result<()> where W: Write { let bytes = v.to_be_bytes(); f.write_all(&bytes) } -fn write_u32be(f: &mut File, v: u32) -> io::Result<()> +fn write_u32be<W>(f: &mut W, v: u32) -> io::Result<()> where W: Write { let bytes = v.to_be_bytes(); f.write_all(&bytes) } -fn write_varlen(f: &mut File, v: u32) -> io::Result<()> +fn write_varlen<W>(f: &mut W, v: u32) -> io::Result<()> where W: Write { if v > 0x0fffffff { return Err(io::Error::new(io::ErrorKind::InvalidData, "Invalid variable length value")); } @@ -103,7 +105,7 @@ fn write_varlen(f: &mut File, v: u32) -> io::Result<()> f.write_all(&buf[..]) } -fn write_raw_event(f: &mut File, re: &RawMidiEvent) -> io::Result<()> +fn write_raw_event<W>(f: &mut W, re: &RawMidiEvent) -> io::Result<()> where W: Write { let mut buf: Vec<u8> = Vec::new(); buf.push(re.ty); @@ -113,23 +115,26 @@ fn write_raw_event(f: &mut File, re: &RawMidiEvent) -> io::Result<()> f.write_all(&buf[..]) } -fn write_track(f: &mut File, trk: &MidiTrack) -> io::Result<()> +fn write_track<W>(f: &mut W, trk: &MidiTrack) -> io::Result<()> where W: Write { let header = "MTrk".as_bytes(); f.write_all(header)?; + let mut buf: Vec<u8> = Vec::new(); let mut curt = 0u32; for te in trk { let TimedMidiEvent{t, e} = te; - write_varlen(f, t - curt)?; + write_varlen(&mut buf, t - curt)?; curt = *t; let re = RawMidiEvent::from(e); - write_raw_event(f, &re)?; + write_raw_event(&mut buf, &re)?; } + write_u32be(f, buf.len() as u32)?; + f.write_all(&buf[..])?; Ok(()) } -fn write_file(filename: &str, mf: &MidiFile) -> io::Result<()> +pub fn write_file(filename: &str, mf: &MidiFile) -> io::Result<()> { let mut f = File::create(filename)?; let header = "MThd".as_bytes(); |