use chordparser::{parsing::Parser, voicings::generate_voicing};
use midly::{
Format, Header, MetaMessage, Smf, Timing, Track, TrackEvent, TrackEventKind,
num::{u4, u7},
};
use std::path::Path;
pub fn main() {
let mut parser = Parser::new();
let origin = "CMaj9#11";
let result = parser.parse(origin);
match result {
Ok(chord) => {
dbg!(&chord);
println!("{}", chord.to_json());
let d5_midi_code = 74;
let midi_codes = generate_voicing(&chord, Some(d5_midi_code));
to_midi_file(&midi_codes, Path::new("my_chord"), 120, 4);
}
Err(e) => {
for e in e.errors {
println!("{}", format!("{}", e.verbose_display(origin)));
}
}
}
}
pub fn to_midi_file(chord_notes: &[u8], name: &Path, bpm: u32, beats: u16) {
let mc_x_beat = 60 * 1_000_000 / bpm;
let ticks_per_beat: u16 = 500;
let ticks_per_quarter = ticks_per_beat * beats;
let velocity = u7::new(64);
let note_duration = ticks_per_quarter;
let mut events = vec![];
let tempo = midly::MetaMessage::Tempo(mc_x_beat.into());
events.push(TrackEvent {
delta: 0.into(),
kind: TrackEventKind::Meta(tempo),
});
for (i, ¬e) in chord_notes.iter().enumerate() {
events.push(TrackEvent {
delta: 0.into(), kind: TrackEventKind::Midi {
channel: u4::new(0),
message: midly::MidiMessage::NoteOn {
key: u7::new(note),
vel: velocity - (i as u8).into(),
},
},
});
}
for (i, ¬e) in chord_notes.iter().enumerate() {
events.push(TrackEvent {
delta: if i == 0 {
(note_duration as u32).into()
} else {
0.into()
},
kind: TrackEventKind::Midi {
channel: u4::new(0),
message: midly::MidiMessage::NoteOff {
key: u7::new(note),
vel: velocity - (i as u8).into(),
},
},
});
}
events.push(TrackEvent {
delta: 0.into(),
kind: TrackEventKind::Meta(MetaMessage::EndOfTrack),
});
let mut track = Track::new();
for event in events {
track.push(event);
}
let smf = Smf {
header: Header {
format: Format::SingleTrack,
timing: Timing::Metrical(midly::num::u15::new(ticks_per_beat)),
},
tracks: vec![track],
};
let path = name.with_extension("mid");
let mut file = std::fs::File::create(path).unwrap();
smf.write_std(&mut file).unwrap();
}