Skip to content

Instantly share code, notes, and snippets.

@LucasAlfare
Last active May 1, 2024 05:52
Show Gist options
  • Save LucasAlfare/e7bb49f1d598f00e6b85a67c3a2d4ea7 to your computer and use it in GitHub Desktop.
Save LucasAlfare/e7bb49f1d598f00e6b85a67c3a2d4ea7 to your computer and use it in GitHub Desktop.
draft: MIDI file reader in Rust (Format Spec. 1.1)
#![allow(unused)]
use std::{
fs::{self, File},
io::Read,
};
fn main() {
let bytes = read_file_bytes("demo.mid");
let mut reader = MyReader::new(bytes);
println!("{:?}", reader);
let header_signature = reader.read_string(4);
println!("header signature={:?}", header_signature);
let header_length = reader.read_4_bytes();
println!("header length={:?}", header_length);
let header_format = reader.read_2_bytes();
println!("header format={:?}", header_format);
let header_num_tracks = reader.read_2_bytes();
println!("header num tracks={:?}", header_num_tracks);
let header_time_division = reader.read_2_bytes();
println!("header time division={:?}", header_time_division);
println!("---TRACKS---");
for i in 0..header_num_tracks {
// for i in 0..1 {
let track_signature = reader.read_string(4);
println!("track {:?} signature={:?}", i, track_signature);
let track_length = reader.read_4_bytes();
println!("\tlength={:?}", track_length);
let mut previous_status = 0;
loop {
let delta_time = reader.read_variable_length_value();
let mut current_status = reader.read_1_byte();
if current_status >> 7 == 0 {
current_status = previous_status;
reader.offset -= 1;
}
match current_status {
// Meta Events
0xFF => {
let kind = reader.read_1_byte();
match kind {
// text event, copyright notice, track name, instrument name, lyric,
// marker, cue point
0x01 | 0x02 | 0x03 | 0x04 | 0x05 | 0x06 | 0x07 => {
let text_data_length = reader.read_variable_length_value();
let text_data = reader.read_string(text_data_length);
println!(
"\tmeta event={:#04x}; delta time={:?}; data={:?}",
kind, delta_time, text_data
);
}
// time signature
0x58 => {
let num_data_items = reader.read_1_byte();
let upper_signature_value = reader.read_1_byte();
let power_of_two_to_lower_value = reader.read_1_byte();
let num_midi_clocks_in_metronome_click = reader.read_1_byte();
let num_of_32nd_notes_in_24_midi_clocks = reader.read_1_byte();
println!(
"\tmeta event={:#04x}; delta time={:?}; data=[{:?}, {:?}, {:?}, {:?}]",
kind,
delta_time,
upper_signature_value,
power_of_two_to_lower_value,
num_midi_clocks_in_metronome_click,
num_of_32nd_notes_in_24_midi_clocks
);
}
// set tempo in microseconds per quarter note
0x51 => {
let num_data_items = reader.read_1_byte();
let tempo_in_microseconds = reader.read_3_bytes();
println!(
"\tmeta event={:#04x}; delta time={:?}; data=[{:?}]",
kind, delta_time, tempo_in_microseconds
);
}
// SMPTE Offset
0x54 => {
let data_length = reader.read_1_byte();
println!(
"\tmeta event={:#04x}; delta time={:?}; data=[{:?}, {:?}, {:?}, {:?}, {:?}]",
kind,
delta_time,
reader.read_1_byte(),
reader.read_1_byte(),
reader.read_1_byte(),
reader.read_1_byte(),
reader.read_1_byte()
);
}
// key signature
0x59 => {
let data_length = reader.read_1_byte();
println!(
"\tmeta event={:#04x}; delta time={:?}; data=[{:?}, {:?}]",
kind,
delta_time,
reader.read_1_byte(),
reader.read_1_byte()
);
}
// end of track
0x2F => {
let data_length = reader.read_1_byte();
println!(
"\tmeta event={:#04x}; delta time={:?}; data=[no data]",
kind, delta_time
);
break;
}
// midi channel prefix
0x20 => {
let data_length = reader.read_1_byte();
let current_effective_midi_channel = reader.read_1_byte();
println!(
"\tmeta event={:#04x}; delta time={:?}; data=[{:?}]",
kind, delta_time, current_effective_midi_channel
);
}
// sequencer specific meta event
0x7f => {
let data_length = reader.read_variable_length_value();
let mut aux_bytes = Vec::<u8>::new();
for i in 0..data_length {
aux_bytes.push(reader.read_1_byte());
}
println!(
"\tmeta event={:#04x}; delta time={:?};data =[{:?}]",
kind, delta_time, aux_bytes
);
}
_ => {
println!(
"Unhandled meta event kind: [{:#04x}]; delta time={:?}",
kind, delta_time
);
}
}
}
// System Exclusive Events
0xF0 | 0xF7 => {
// pass...
}
// Control Events
_ => {
previous_status = current_status;
let kind = current_status >> 4;
let target_channel = current_status & 0b1111;
match kind {
// select instrument
0b1100 => {
let target_instrument = reader.read_1_byte();
println!(
"\tcontrol event={:#04b}; delta time={:?}; data =[{:?}]",
kind, delta_time, target_instrument
);
}
// note on, note off
0b1001 | 0b1000 => {
let note_number = reader.read_1_byte() & 0b01111111;
let note_velocity = reader.read_1_byte() & 0b01111111;
println!(
"\tcontrol event={:#04b}; delta time={:?}; data =[{:?}, {:?}]",
kind, delta_time, note_number, note_velocity
);
}
// channel mode
0b1011 => {
let channel_mode_type_code = reader.read_1_byte();
let channel_mode_arg_1 = reader.read_1_byte();
let channel_mode_arg_2 = reader.read_1_byte();
println!(
"\tcontrol event={:#04b}; delta time={:?}; data =[{:?}, {:?}, {:?}]",
kind, delta_time, channel_mode_type_code, channel_mode_arg_1, channel_mode_arg_2
);
}
// channel pressure
0b1101 => {
let channel_pressure = reader.read_1_byte();
println!(
"\tcontrol event={:#04b}; delta time={:?}; data =[{:?}]",
kind, delta_time, channel_pressure
);
}
0b1110 => {
let pitch_bend = reader.read_1_byte();
println!(
"\tcontrol event={:#04b}; delta time={:?}; data =[{:?}]",
kind, delta_time, pitch_bend
);
}
_ => {
println!(
"Unhandled control event kind: [{:#04b}]; delta time={:?}",
kind, delta_time
);
break;
}
}
}
}
}
}
}
fn read_file_bytes(pathname: &str) -> Vec<u8> {
let file_len = fs::metadata(pathname).unwrap().len();
let mut buffer = vec![0; file_len as usize];
let mut file = File::open(pathname).unwrap();
let _ = file.read(&mut buffer);
buffer
}
fn debug_hex(n: u8, indents: u8) {
for i in 0..indents {
print!("\t");
}
println!("{:#04x}", n);
}
#[derive(Debug)]
pub struct MyReader {
pub buffer: Vec<u8>,
pub offset: u32,
}
impl MyReader {
pub fn new(buffer: Vec<u8>) -> Self {
MyReader { buffer, offset: 0 }
}
pub fn read_1_byte(&mut self) -> u8 {
let result = self.buffer[self.offset as usize];
self.offset += 1;
return result;
}
pub fn read_2_bytes(&mut self) -> u16 {
let a = self.buffer[(self.offset) as usize] as u16;
let b = self.buffer[(self.offset + 1) as usize] as u16;
let result = (a << 8) | b;
self.offset += 2;
result
}
pub fn read_3_bytes(&mut self) -> u32 {
let a = self.buffer[(self.offset + 0) as usize] as u32;
let b = self.buffer[(self.offset + 1) as usize] as u32;
let c = self.buffer[(self.offset + 2) as usize] as u32;
let result = (((a << 8) | b) << 16) | c;
self.offset += 3;
return result;
}
pub fn read_4_bytes(&mut self) -> u32 {
let a = self.buffer[(self.offset + 0) as usize] as u32;
let b = self.buffer[(self.offset + 1) as usize] as u32;
let c = self.buffer[(self.offset + 2) as usize] as u32;
let d = self.buffer[(self.offset + 3) as usize] as u32;
let result = (((((a << 24) | b) << 16) | c) << 8) | d;
self.offset += 4;
return result;
}
pub fn read_string(&mut self, length: u32) -> String {
let mut result = String::new();
for i in 0..length {
let curr_byte = self.buffer[(self.offset + i) as usize];
result.push(curr_byte as char);
}
self.offset += length;
return result;
}
pub fn read_variable_length_value(&mut self) -> u32 {
let mask: u8 = 0b0111_1111;
let mut result_number: u32 = 0;
let mut current_byte: u8;
loop {
current_byte = self.read_1_byte();
result_number = (result_number << 7) | ((current_byte & mask) as u32);
if current_byte >> 7 == 0 {
return result_number;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment