From de6dd59e484ce086832c8414ad79e911cae92708 Mon Sep 17 00:00:00 2001 From: Nicole Tietz-Sokolskaya <me@ntietz.com> Date: Sun, 8 Dec 2024 22:07:14 -0500 Subject: [PATCH] start some ui, refactor midi library a bit --- Cargo.toml | 2 ++ src/bin/main.rs | 6 +++++- src/lib.rs | 1 + src/midi.rs | 1 + src/parser.rs | 15 +++------------ src/ui.rs | 41 +++++++++++++++++++++++++++++++++++++++++ 6 files changed, 53 insertions(+), 13 deletions(-) create mode 100644 src/ui.rs diff --git a/Cargo.toml b/Cargo.toml index d06cbea..3d493c0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,8 @@ edition = "2021" [dependencies] anyhow = "1.0.86" +eframe = "0.29.1" +egui = "0.29.1" enigo = { version = "0.2.1", features = ["serde"] } hex = "0.4.3" midir = "0.10.0" diff --git a/src/bin/main.rs b/src/bin/main.rs index 20b9933..78d6c3e 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -13,6 +13,8 @@ fn main() { //enigo.text("echo \"hello world\"").unwrap(); //enigo.key(Key::Return, Direction::Press).unwrap(); + midi_keys::ui::run(); + match run() { Ok(_) => {} Err(err) => { @@ -28,7 +30,7 @@ fn run() -> Result<()> { Ok(m) => m, Err(e) => { println!("error: {}", e); - return replay_file("assets/windsynth.log"); + return Ok(()); } }; let port_name = midi_in.port_name(&midi_device)?; @@ -49,6 +51,8 @@ fn run() -> Result<()> { let mut buf = String::new(); stdin().read_line(&mut buf)?; + // TODO + let _ = replay_file("assets/windsynth.log"); Ok(()) } diff --git a/src/lib.rs b/src/lib.rs index 535cd1e..7920f79 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,4 @@ pub mod log; pub mod midi; pub mod parser; +pub mod ui; diff --git a/src/midi.rs b/src/midi.rs index fe4d0b9..46ffd53 100644 --- a/src/midi.rs +++ b/src/midi.rs @@ -26,6 +26,7 @@ pub enum VoiceCategory { ProgramChange { value: u8 }, ChannelPressure { pressure: u8 }, PitchWheel { value: u16 }, + Unknown, } #[derive(PartialEq, Eq, Debug, Clone)] diff --git a/src/parser.rs b/src/parser.rs index 43b7c20..0b7cadf 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -42,10 +42,7 @@ fn parse_system_common(status_byte: u8, bytes: &[u8]) -> IResult<&[u8], SystemCo song_number, }), 0xf6 => Ok((bytes, SystemCommon::TuneRequest)), - _ => Err(nom::Err::Error(nom::error::Error { - input: bytes, - code: nom::error::ErrorKind::Fail, - })), + _ => Ok((bytes, SystemCommon::Unknown)), } } @@ -66,7 +63,6 @@ pub fn parse_voice_message(status_byte: u8, remainder: &[u8]) -> IResult<&[u8], let category_nibble = 0xf0 & status_byte; let channel = 0x0f & status_byte; - println!("category_nibble = {:#x}", category_nibble); let (remainder, category) = match category_nibble { 0x80 => parse_voice_note(remainder, true)?, 0x90 => parse_voice_note(remainder, false)?, @@ -82,12 +78,7 @@ pub fn parse_voice_message(status_byte: u8, remainder: &[u8]) -> IResult<&[u8], pressure, })?, 0xe0 => parse_pitch_wheel(remainder)?, - _ => { - return Err(nom::Err::Error(nom::error::Error { - input: remainder, - code: nom::error::ErrorKind::Fail, - })) - } + _ => (remainder, VoiceCategory::Unknown), }; Ok((remainder, VoiceMessage::new(category, channel))) @@ -110,7 +101,7 @@ pub fn parse_pitch_wheel(bytes: &[u8]) -> IResult<&[u8], VoiceCategory> { pub fn parse_system_exclusive(bytes: &[u8]) -> IResult<&[u8], SystemCommon> { let (remainder, data) = take_till(is_status_byte)(bytes)?; - let (remainder, _) = opt(tag([0xf7]))(remainder)?; + let (remainder, _) = tag([0xf7])(remainder)?; let data: Vec<u8> = data.into(); diff --git a/src/ui.rs b/src/ui.rs new file mode 100644 index 0000000..b97d7a0 --- /dev/null +++ b/src/ui.rs @@ -0,0 +1,41 @@ +use std::time::Instant; + +/// Launches the UI and runs it until it's done executing. +pub fn run() { + let native_options = eframe::NativeOptions::default(); + // TODO: don't ignore result + let _ = eframe::run_native( + "Midi Keys", + native_options, + Box::new(|cc| Ok(Box::new(MidiKeysApp::new(cc)))), + ); +} + +struct MidiKeysApp { + previous_frame_time: Instant, +} + +impl MidiKeysApp { + fn new(_cc: &eframe::CreationContext<'_>) -> Self { + // this is where to hook in for customizing eguji, like fonts and visuals. + + let previous_frame_time = Instant::now(); + MidiKeysApp { + previous_frame_time, + } + } +} + +impl eframe::App for MidiKeysApp { + fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) { + let duration = self.previous_frame_time.elapsed().as_secs_f32(); + self.previous_frame_time = Instant::now(); + + egui::CentralPanel::default().show(ctx, |ui| { + ui.heading("Hello world"); + + let framerate = format!("{:>8.2}", 1. / duration); + ui.label(framerate); + }); + } +}