tek/src/sequence/midi.rs
2024-07-04 01:36:30 +03:00

114 lines
3.7 KiB
Rust

use crate::sequence::{Frame, Time};
/// Pulses per quarter note
pub const PPQ: usize = 96;
pub struct Message {
bytes: Vec<u8>
}
pub struct MIDISequence {
name: String,
length: usize,
events: Vec<(Frame, MIDIEvent)>,
notes: Vec<u8>,
}
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<dyn std::error::Error>>
{
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)
}