From 2c6dbbf952b822f2c48eb44a0ef9e6194ebe2218 Mon Sep 17 00:00:00 2001
From: Nicole Tietz-Sokolskaya <me@ntietz.com>
Date: Sun, 10 Nov 2024 16:21:27 -0500
Subject: [PATCH] finish parsing voice messages

---
 src/bin/main.rs |  8 ++++----
 src/midi.rs     |  4 ++--
 src/parser.rs   | 30 +++++++++++++++++++++++++++---
 3 files changed, 33 insertions(+), 9 deletions(-)

diff --git a/src/bin/main.rs b/src/bin/main.rs
index a90e2b4..20b9933 100644
--- a/src/bin/main.rs
+++ b/src/bin/main.rs
@@ -1,6 +1,6 @@
 use std::{
     fs::File,
-    io::{stdin, Read, Write},
+    io::{stdin, Write},
 };
 
 use anyhow::{anyhow, Result};
@@ -65,9 +65,9 @@ fn handle_midi_event(timestamp: u64, message: &[u8], file: &mut Option<File>) {
         let ts_buf = timestamp.to_be_bytes();
         let len_buf = message.len().to_be_bytes();
 
-        file.write(&ts_buf).unwrap();
-        file.write(&len_buf).unwrap();
-        file.write(message).unwrap();
+        file.write_all(&ts_buf).unwrap();
+        file.write_all(&len_buf).unwrap();
+        file.write_all(message).unwrap();
     }
 
     let hex_msg = hex::encode(message);
diff --git a/src/midi.rs b/src/midi.rs
index d7a0e9e..078d5ca 100644
--- a/src/midi.rs
+++ b/src/midi.rs
@@ -20,10 +20,10 @@ impl VoiceMessage {
 pub enum VoiceCategory {
     NoteOff { note: u8, velocity: u8 },
     NoteOn { note: u8, velocity: u8 },
-    AfterTouch,
+    AfterTouch { note: u8, pressure: u8 },
     ControlChange { controller: u8, value: u8 },
     ProgramChange { value: u8 },
-    ChannelPressure,
+    ChannelPressure { pressure: u8 },
     PitchWheel { value: u16 },
 }
 
diff --git a/src/parser.rs b/src/parser.rs
index c7f040a..a04d9f8 100644
--- a/src/parser.rs
+++ b/src/parser.rs
@@ -16,10 +16,10 @@ pub fn parse_message(bytes: &[u8]) -> IResult<&[u8], Message> {
 }
 
 fn parse_status_message(_status_byte: u8, bytes: &[u8]) -> IResult<&[u8], SystemMessage> {
-    return Err(nom::Err::Error(nom::error::Error {
+    Err(nom::Err::Error(nom::error::Error {
         input: bytes,
         code: nom::error::ErrorKind::Fail,
-    }));
+    }))
 }
 
 pub fn parse_voice_message(status_byte: u8, remainder: &[u8]) -> IResult<&[u8], VoiceMessage> {
@@ -30,8 +30,10 @@ pub fn parse_voice_message(status_byte: u8, remainder: &[u8]) -> IResult<&[u8],
     let (remainder, category) = match category_nibble {
         0x80 => parse_voice_note(remainder, true)?,
         0x90 => parse_voice_note(remainder, false)?,
+        0xa0 => parse_aftertouch(remainder)?,
         0xb0 => parse_control_change(remainder)?,
         0xc0 => parse_program_change(remainder)?,
+        0xd0 => parse_channel_pressure(remainder)?,
         0xe0 => parse_pitch_wheel(remainder)?,
         _ => {
             return Err(nom::Err::Error(nom::error::Error {
@@ -92,7 +94,7 @@ pub fn parse_control_change(bytes: &[u8]) -> IResult<&[u8], VoiceCategory> {
 }
 
 pub fn parse_program_change(bytes: &[u8]) -> IResult<&[u8], VoiceCategory> {
-    if bytes.len() < 1 {
+    if bytes.is_empty() {
         return Err(generic_error(bytes));
     }
 
@@ -100,6 +102,28 @@ pub fn parse_program_change(bytes: &[u8]) -> IResult<&[u8], VoiceCategory> {
 
     Ok((&bytes[1..], VoiceCategory::ProgramChange { value }))
 }
+
+pub fn parse_aftertouch(bytes: &[u8]) -> IResult<&[u8], VoiceCategory> {
+    if bytes.len() < 2 {
+        return Err(generic_error(bytes));
+    }
+
+    let note = bytes[0];
+    let pressure = bytes[1];
+
+    Ok((&bytes[2..], VoiceCategory::AfterTouch { note, pressure }))
+}
+
+pub fn parse_channel_pressure(bytes: &[u8]) -> IResult<&[u8], VoiceCategory> {
+    if bytes.is_empty() {
+        return Err(generic_error(bytes));
+    }
+
+    let pressure = bytes[0];
+
+    Ok((&bytes[1..], VoiceCategory::ChannelPressure { pressure }))
+}
+
 #[cfg(test)]
 mod tests {
     use crate::{log::load_raw_log, midi::VoiceMessage};