use crate::sequence::{Frame, Time}; /// Pulses per quarter note pub const PPQ: usize = 96; pub struct Message { bytes: Vec } pub struct MIDISequence { name: String, length: usize, events: Vec<(Frame, MIDIEvent)>, notes: Vec, } impl MIDISequence { pub fn new (name: &str, length: usize) -> Self { Self { name: name.to_string(), length, events: vec![], notes: vec![], } } pub fn add (&mut self, time: usize, event: MIDIEvent) -> &mut Self { let mut sort = false; match &event { MIDIEvent::NoteOn(pitch, _velocity) => { if !self.notes.contains(pitch) { self.notes.push(*pitch); sort = true; } } } if sort { self.notes.sort(); } self.events.push((time, event)); self } pub fn render (&self, stdout: &mut std::io::Stdout, resolution: usize) -> Result<(), Box> { use crossterm::{*, style::Stylize}; let (col, row) = cursor::position()?; let unit = PPQ / resolution; let length = self.length / unit; let mut header = String::from(" "); for i in 0..length { if i % 8 == 0 { header.push('┍'); } else { header.push('━'); } } header.push('┑'); let mut tracks: Vec<(String, String)> = vec![]; for note in self.notes.iter().rev() { let mut row_header = format!(" {note:3} "); let mut row = String::new(); for beat in 0..length { let mut active = false; for (frame, event) in self.events.iter() { match event { MIDIEvent::NoteOn(pitch, _) => { if pitch == note && *frame >= beat * unit && *frame < (beat + 1) * unit { active = true; continue } } } } if active { row.push('⯀') } else if beat == 0 { row.push('│'); } else if beat % 8 == 0 { row.push('┆'); } else { row.push('·'); } } tracks.push((row_header, row)); } stdout.queue(style::PrintStyledContent(header.grey()))?; for (row_header, row) in tracks.into_iter() { stdout .queue(cursor::MoveDown(1))? .queue(cursor::MoveToColumn(col))? .queue(style::PrintStyledContent(row_header.grey()))? .queue(style::PrintStyledContent(row.clone().white()))? .queue(style::PrintStyledContent(row.clone().yellow()))? .queue(style::PrintStyledContent(row.white()))?; } //stdout //.queue(cursor::MoveDown(1))? //.queue(cursor::MoveToColumn(col))? //.queue(style::PrintStyledContent(footer.grey()))?; //.queue(style::PrintStyledContent("················".grey()))? //.queue(style::PrintStyledContent("│".yellow()))? //.queue(cursor::MoveDown(1))? //.queue(cursor::MoveLeft(18))? //.queue(style::PrintStyledContent("└────────────────┘".yellow()))?; Ok(()) } } pub enum MIDIEvent { NoteOn(u8, u8) }