use anyhow::{Result, anyhow}; use macroquad::color::*; use serialport::SerialPortType; #[derive(Clone, Copy, Debug)] pub enum Instruction { NoteOn(u8), NoteOff, Modulation { depth: u8, rate: u8 }, Frequency(u16), } pub struct SerialDevice { port: Box, } const CHANNEL_COUNT: u8 = 4; impl SerialDevice { pub fn new() -> Result { let ports = serialport::available_ports()?; let mut this: anyhow::Result = Err(anyhow!("No serial port found")); for port in ports { match port.port_type { SerialPortType::UsbPort(_) => { this = Ok(Self { port: serialport::new(port.port_name, 115200).open()?, }); break; } _ => {} }; } this } fn note_off(&mut self, ch: u8) -> Result<()> { assert!((0..CHANNEL_COUNT).contains(&ch)); let bytes: Vec = vec![0x80 + ch]; self.port.write(&bytes)?; Ok(()) } fn note_on(&mut self, ch: u8, note: u8) -> Result<()> { assert!((0..CHANNEL_COUNT).contains(&ch)); assert!((0..=127).contains(¬e)); let bytes: Vec = vec![0x90 + ch, note]; self.port.write(&bytes)?; Ok(()) } fn modulation(&mut self, ch: u8, depth: u8, rate: u8) -> Result<()> { assert!((0..CHANNEL_COUNT).contains(&ch)); assert!((0..=127).contains(&depth)); let bytes: Vec = vec![0xA0 + ch, depth, rate]; self.port.write(&bytes)?; Ok(()) } fn frequency_on(&mut self, ch: u8, freq: u16) -> Result<()> { assert!((0..CHANNEL_COUNT).contains(&ch)); let bytes: Vec = vec![0xB0 + ch, (freq & 0xff) as u8, (freq >> 8) as u8]; self.port.write(&bytes)?; Ok(()) } pub fn stop(&mut self) -> Result<()> { let bytes: Vec = vec![0xff]; self.port.write(&bytes)?; Ok(()) } pub fn execute(&mut self, ch: u8, instruction: Instruction) -> Result<()> { match instruction { Instruction::NoteOn(note) => self.note_on(ch, note), Instruction::NoteOff => self.note_off(ch), Instruction::Modulation { depth, rate } => self.modulation(ch, depth, rate), Instruction::Frequency(freq) => self.frequency_on(ch, freq), } } } pub struct Pattern { pub rows: Vec<[Option; CHANNEL_COUNT as usize]>, } impl Pattern { pub fn new() -> Self { let mut rows = Vec::new(); rows.resize_with(256, || [None; CHANNEL_COUNT as usize]); Self { rows } } } pub struct TimeSignature { pub numerator: u8, pub denominator: u8, } impl Default for TimeSignature { fn default() -> Self { Self { numerator: 4, denominator: 4, } } } pub struct Song { pub bpm: f64, pub time_signature: TimeSignature, pub patterns: Vec, pub pattern_order: Vec, // index into patterns } impl Song { const DEFAULT_BPM: f64 = 120.0; pub fn new(bpm: Option, time_signature: Option) -> Self { Self { bpm: bpm.unwrap_or(Self::DEFAULT_BPM), time_signature: time_signature.unwrap_or_default(), patterns: vec![Pattern::new()], pattern_order: vec![0], } } pub fn empty(bpm: Option, time_signature: Option) -> Self { Self { bpm: bpm.unwrap_or(Self::DEFAULT_BPM), time_signature: time_signature.unwrap_or_default(), patterns: Vec::new(), pattern_order: Vec::new(), } } } #[derive(Default)] struct App {} impl App { pub fn new() -> Self { Self { ..App::default() } } pub async fn run(&self) { loop { self.update().await; } } async fn update(&self) { macroquad::window::clear_background(WHITE); macroquad::shapes::draw_line(40.0, 40.0, 100.0, 200.0, 15.0, BLUE); macroquad::shapes::draw_rectangle( macroquad::window::screen_width() / 2.0 - 60.0, 100.0, 120.0, 60.0, GREEN, ); macroquad::text::draw_text("Hello, Macroquad!", 20.0, 20.0, 30.0, DARKGRAY); macroquad::window::next_frame().await } } #[macroquad::main("singer")] async fn main() { let app = App::new(); app.run().await; }