345 lines
9.9 KiB
Rust
345 lines
9.9 KiB
Rust
use std::fs::File;
|
|
use std::io::prelude::*;
|
|
use std::io::Error;
|
|
|
|
fn buffer_u16(b: &[u8]) -> u16 {
|
|
(b[0] as u16) << 8 | b[1] as u16
|
|
}
|
|
fn buffer_u32(b: &[u8]) -> u32 {
|
|
(b[0] as u32) << 24 | (b[1] as u32) << 16 | (b[2] as u32) << 8 | (b[3] as u32)
|
|
}
|
|
|
|
struct MidiHeader {
|
|
tamanho: u32,
|
|
formato: u16,
|
|
tracks: u16,
|
|
divisao: u16,
|
|
}
|
|
|
|
fn ler_vlq(buffer_completo: Vec<u8>) -> (u32, Vec<u8>) {
|
|
let mut dt;
|
|
let mut dtb;
|
|
let (p, mut resto) = buffer_completo.split_at(1);
|
|
|
|
dt = p[0] as u32;
|
|
dtb = p[0];
|
|
|
|
while dtb & 0b10000000 != 0 {
|
|
dt &= 0x7f;
|
|
dt = dt << 7;
|
|
let tmp = resto.split_at(1);
|
|
dtb = tmp.0[0];
|
|
resto = tmp.1;
|
|
dt = dt | (dtb & 0x7f) as u32;
|
|
}
|
|
|
|
return (dt, Vec::from(resto));
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
#[derive(Clone, Debug)]
|
|
enum TipoMetaEvento {
|
|
SequenceNumber,
|
|
TextEvent(String),
|
|
CopyrightNotice(String),
|
|
TrackName(String),
|
|
InstrumentName(String),
|
|
Lyric(String),
|
|
Marker(String),
|
|
CuePoint(String),
|
|
SetTempo(u32),
|
|
MIDIChannelPrefix,
|
|
EndofTrack,
|
|
SMTPEOffset,
|
|
TimeSignature,
|
|
KeySignature,
|
|
SequencerSpecificMetaEvent,
|
|
}
|
|
|
|
#[derive(Clone, Debug)]
|
|
struct MetaEvento {
|
|
tipo: u8,
|
|
tamanho: u32,
|
|
dados: Vec<u8>,
|
|
estrutura: TipoMetaEvento,
|
|
}
|
|
|
|
impl MetaEvento {
|
|
fn novo(tipo: u8, tamanho: u32, dados: Vec<u8>) -> Self {
|
|
unsafe {
|
|
let estrutura = match tipo {
|
|
0x00 => TipoMetaEvento::SequenceNumber,
|
|
0x01 => TipoMetaEvento::TextEvent(String::from_utf8(dados.clone()).unwrap()),
|
|
0x02 => TipoMetaEvento::CopyrightNotice(String::from_utf8_unchecked(dados.clone())),
|
|
0x03 => TipoMetaEvento::TrackName(String::from_utf8(dados.clone()).unwrap()),
|
|
0x04 => TipoMetaEvento::InstrumentName(String::from_utf8(dados.clone()).unwrap()),
|
|
0x05 => TipoMetaEvento::Lyric(String::from_utf8(dados.clone()).unwrap()),
|
|
0x06 => TipoMetaEvento::Marker(String::from_utf8(dados.clone()).unwrap()),
|
|
0x07 => TipoMetaEvento::CuePoint(String::from_utf8(dados.clone()).unwrap()),
|
|
0x20 => TipoMetaEvento::MIDIChannelPrefix,
|
|
0x2F => TipoMetaEvento::EndofTrack,
|
|
0x54 => TipoMetaEvento::SMTPEOffset,
|
|
0x58 => TipoMetaEvento::TimeSignature,
|
|
0x59 => TipoMetaEvento::KeySignature,
|
|
0x51 => TipoMetaEvento::SetTempo(
|
|
(dados[0] as u32) << 16 | (dados[1] as u32) << 8 | (dados[2] as u32),
|
|
),
|
|
_ => TipoMetaEvento::SequencerSpecificMetaEvent,
|
|
};
|
|
|
|
MetaEvento {
|
|
tamanho,
|
|
tipo,
|
|
dados,
|
|
estrutura,
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
//#[derive(Clone)]
|
|
//struct SysexEvento {
|
|
// tipo: u8,
|
|
// tamanho: u32,
|
|
// dados: Vec<u8>,
|
|
//}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub enum TipoMidiEvento {
|
|
NotaOn(u8, u8),
|
|
NotaOff(u8, u8),
|
|
Nenhum,
|
|
}
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub struct MidiEvento {
|
|
estrutura: TipoMidiEvento,
|
|
}
|
|
|
|
impl MidiEvento {
|
|
fn novo(tipo: u8, _canal: u8, dados: Vec<u8>) -> Self {
|
|
let estrutura = match tipo {
|
|
0x8 => TipoMidiEvento::NotaOff(dados[0], dados[1]),
|
|
0x9 => TipoMidiEvento::NotaOn(dados[0], dados[1]),
|
|
_ => TipoMidiEvento::Nenhum,
|
|
};
|
|
|
|
MidiEvento { estrutura }
|
|
}
|
|
|
|
pub fn som(&self) -> (u8, u8) {
|
|
match self.estrutura {
|
|
TipoMidiEvento::NotaOn(n, v) => (n, v),
|
|
TipoMidiEvento::NotaOff(n, v) => (n, v),
|
|
_ => (0, 0),
|
|
}
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
#[derive(Clone, Debug)]
|
|
pub enum Evento {
|
|
Vazio,
|
|
Meta(MetaEvento),
|
|
//Sysex(SysexEvento),
|
|
Midi(MidiEvento),
|
|
}
|
|
|
|
#[derive(Clone)]
|
|
struct MidiTrack {
|
|
tamanho: u32,
|
|
d_eventos: Vec<(u32, Evento)>,
|
|
buffer_eventos: Vec<u8>,
|
|
}
|
|
|
|
impl MidiTrack {
|
|
pub fn tt(&self) {
|
|
println!("{}", self.d_eventos.len());
|
|
}
|
|
|
|
fn processar(&mut self) -> Result<(), Error> {
|
|
let mut buffer_completo = self.buffer_eventos.clone();
|
|
loop {
|
|
if buffer_completo.is_empty() {
|
|
break;
|
|
}
|
|
let (dt, mut resto) = ler_vlq(buffer_completo);
|
|
|
|
let tmp = resto.split_at(1);
|
|
let status = tmp.0[0];
|
|
resto = tmp.1.to_vec();
|
|
|
|
let evento = match status {
|
|
0xff => {
|
|
//Meta evento
|
|
let tmp = resto.split_at(1);
|
|
let tipo = tmp.0[0];
|
|
resto = tmp.1.to_vec();
|
|
|
|
let tmp = ler_vlq(resto);
|
|
let tamanho = tmp.0;
|
|
resto = tmp.1;
|
|
|
|
let tmp = resto.split_at(tamanho as usize);
|
|
let dados = tmp.0.to_vec();
|
|
resto = tmp.1.to_vec();
|
|
|
|
Evento::Meta(MetaEvento::novo(tipo, tamanho, dados))
|
|
}
|
|
0x80..=0xef => {
|
|
//Evento midi
|
|
let tipo = (status & 0b11110000) >> 4;
|
|
let canal = status & 0b00001111;
|
|
|
|
let evento;
|
|
|
|
match tipo {
|
|
0x8 => {
|
|
let tmp = resto.split_at(2);
|
|
evento = Evento::Midi(MidiEvento::novo(tipo, canal, tmp.0.to_vec()));
|
|
resto = tmp.1.to_vec();
|
|
}
|
|
0x9 => {
|
|
let tmp = resto.split_at(2);
|
|
evento = Evento::Midi(MidiEvento::novo(tipo, canal, tmp.0.to_vec()));
|
|
resto = tmp.1.to_vec();
|
|
}
|
|
|
|
0xa | 0xb | 0xe => {
|
|
let tmp = resto.split_at(2);
|
|
resto = tmp.1.to_vec();
|
|
evento = Evento::Vazio;
|
|
}
|
|
|
|
0xc => {
|
|
let tmp = resto.split_at(1);
|
|
resto = tmp.1.to_vec();
|
|
evento = Evento::Vazio;
|
|
}
|
|
0xd => {
|
|
let tmp = resto.split_at(1);
|
|
resto = tmp.1.to_vec();
|
|
evento = Evento::Vazio;
|
|
}
|
|
|
|
_ => {
|
|
return Err(Error::new(
|
|
std::io::ErrorKind::InvalidInput,
|
|
format!("evento midi desconhecido : {}", status),
|
|
))
|
|
}
|
|
}
|
|
|
|
evento
|
|
}
|
|
0xf0 | 0xf7 => todo!("implementar eventos sysex tipo 0x{:x?}", status),
|
|
_ => {
|
|
return Err(Error::new(
|
|
std::io::ErrorKind::InvalidInput,
|
|
format!("evento desconhecido : {:x?}", status),
|
|
));
|
|
}
|
|
};
|
|
|
|
self.d_eventos.push((dt, evento));
|
|
buffer_completo = Vec::from(resto);
|
|
}
|
|
|
|
let mut nd_eventos = Vec::new();
|
|
for ev in self.d_eventos.clone() {
|
|
match ev.1 {
|
|
Evento::Vazio => {}
|
|
_ => {
|
|
nd_eventos.push(ev);
|
|
}
|
|
}
|
|
}
|
|
self.d_eventos = nd_eventos;
|
|
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
pub struct MIDI {
|
|
cabecalho: MidiHeader,
|
|
tracks: Vec<MidiTrack>,
|
|
}
|
|
|
|
impl MIDI {
|
|
pub fn tt(&self) {
|
|
let mut tn = 1;
|
|
self.tracks.iter().for_each(|i| {
|
|
print!("track num {} :", tn);
|
|
i.tt();
|
|
tn += 1;
|
|
});
|
|
}
|
|
|
|
pub fn prox(&mut self) -> Option<(u32, Evento)> {
|
|
self.tracks[1].d_eventos.pop()
|
|
}
|
|
|
|
pub fn novo(arquivo: &str) -> Result<Self, Error> {
|
|
let mut f = File::open(arquivo).expect("problema ao abrir o midi");
|
|
let mut buffer_cabecalho = [0; 4];
|
|
let mut buffer_tamanho = [0; 4];
|
|
let mut buffer_formato = [0; 2];
|
|
let mut buffer_tracks = [0; 2];
|
|
let mut buffer_divisao = [0; 2];
|
|
|
|
f.read_exact(&mut buffer_cabecalho)?;
|
|
f.read_exact(&mut buffer_tamanho)?;
|
|
f.read_exact(&mut buffer_formato)?;
|
|
f.read_exact(&mut buffer_tracks)?;
|
|
f.read_exact(&mut buffer_divisao)?;
|
|
|
|
let tamanho = buffer_u32(&buffer_tamanho);
|
|
let formato = buffer_u16(&buffer_formato);
|
|
let tracks = buffer_u16(&buffer_tracks);
|
|
let divisao = buffer_u16(&buffer_divisao);
|
|
|
|
let cabecalho = MidiHeader {
|
|
tamanho,
|
|
formato,
|
|
tracks,
|
|
divisao,
|
|
};
|
|
|
|
let tracks = Vec::new();
|
|
let mut midi_r = MIDI { cabecalho, tracks };
|
|
midi_r.processar_tracks(&mut f)?;
|
|
return Ok(midi_r);
|
|
}
|
|
|
|
fn processar_tracks(&mut self, reader: &mut File) -> Result<(), Error> {
|
|
for _ in 0..self.cabecalho.tracks {
|
|
let mut buffer_cabecalho = [0; 4];
|
|
let mut buffer_tamanho = [0; 4];
|
|
reader.read_exact(&mut buffer_cabecalho)?;
|
|
reader.read_exact(&mut buffer_tamanho)?;
|
|
let tamanho = buffer_u32(&buffer_tamanho);
|
|
let mut buffer_eventos: Vec<u8> = vec![0; tamanho as usize];
|
|
reader.read_exact(&mut buffer_eventos)?;
|
|
|
|
let d_eventos = Vec::new();
|
|
|
|
let mut track = MidiTrack {
|
|
tamanho,
|
|
d_eventos,
|
|
buffer_eventos,
|
|
};
|
|
|
|
track.processar()?;
|
|
track.d_eventos.reverse();
|
|
self.tracks.push(track);
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
}
|