From 50a287d1b53a385bdfa0b05f5e0f686663da3ccd Mon Sep 17 00:00:00 2001 From: Oliver Rockstedt Date: Tue, 14 Jan 2025 18:53:37 +0100 Subject: [PATCH] Use U14 type in pitch wheel and song position pointer messages --- CHANGELOG.md | 6 +++++- src/message/data/u14.rs | 2 +- src/message/mod.rs | 41 ++++++++++++++++++++++++----------------- 3 files changed, 30 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f9678e..7d21278 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,11 +10,15 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Added - `Message` enum variants for *System Common* and *System Realtime* messages. -- `U14` primitive value type. +- `U14` primitive value type used by *Pitch Wheel* and *Song Position Pointer* messages. - Derive `Debug`, `Clone`, `Eq`, and `PartialEq` for `U4`. - Derive `Debug`, `Clone`, `Eq`, and `PartialEq` for `InvalidU4`. - Derive `Debug`, `Clone`, `Eq`, and `PartialEq` for `InvalidU7`. +### Changed + +- Changed pitch wheel `Message` variant from `PitchWheelChange(Channel, U7, U7)` to `PitchWheelChange(Channel, U14)`. + ## [0.4.0] - 2025-01-03 This release focuses on: diff --git a/src/message/data/u14.rs b/src/message/data/u14.rs index 07122e2..74389f8 100644 --- a/src/message/data/u14.rs +++ b/src/message/data/u14.rs @@ -4,7 +4,7 @@ use crate::message::data::{FromClamped, FromOverFlow}; /// A primitive value that can be from 0-0x4000 #[derive(Debug, Clone, Eq, PartialEq)] -pub struct U14(u16); +pub struct U14(pub(crate) u16); /// Error representing that this value is not a valid u14 #[derive(Debug, Clone, Eq, PartialEq)] diff --git a/src/message/mod.rs b/src/message/mod.rs index 35031d6..e8335f7 100644 --- a/src/message/mod.rs +++ b/src/message/mod.rs @@ -8,6 +8,7 @@ pub mod raw; use crate::message::channel::Channel; use crate::message::control_function::ControlFunction; +use crate::message::data::u14::U14; use crate::message::data::u7::U7; use crate::message::data::FromClamped; use crate::message::notes::Note; @@ -36,13 +37,13 @@ pub enum Message { /// Channel aftertouch message. ChannelAftertouch(Channel, U7), /// Pitchwheel message. - PitchWheelChange(Channel, U7, U7), + PitchWheelChange(Channel, U14), /// Control Change (CC) message. ControlChange(Channel, ControlFunction, U7), /// MTC Quarter Frame message. MtcQuarterFrame(U7), /// Song Position Pointer message. - SongPositionPointer(U7, U7), + SongPositionPointer(U14), /// Song Select message. SongSelect(U7), /// Tune Request message. @@ -111,7 +112,10 @@ impl From for Raw { let status = CHANNEL_AFTERTOUCH_MASK | u8::from(chan); Raw { status, payload } } - Message::PitchWheelChange(chan, lsb, msb) => { + Message::PitchWheelChange(chan, value) => { + let value = u16::from(value); + let lsb = U7::try_from((value & 0x7F) as u8).unwrap(); + let msb = U7::try_from(((value >> 7) & 0x7F) as u8).unwrap(); let payload = Payload::DoubleByte(lsb, msb); let status = PITCH_BEND_MASK | u8::from(chan); Raw { status, payload } @@ -126,7 +130,10 @@ impl From for Raw { let status = MTC_QUARTER_FRAME; Raw { status, payload } } - Message::SongPositionPointer(lsb, msb) => { + Message::SongPositionPointer(value) => { + let value = u16::from(value); + let lsb = U7::try_from((value & 0x7F) as u8).unwrap(); + let msb = U7::try_from(((value >> 7) & 0x7F) as u8).unwrap(); let payload = Payload::DoubleByte(lsb, msb); let status = SONG_POSITION_POINTER; Raw { status, payload } @@ -194,10 +201,7 @@ impl TryFrom<&[u8]> for Message { return Ok(Message::MtcQuarterFrame(get_u7_at(data, 1)?)); } SONG_POSITION_POINTER => { - return Ok(Message::SongPositionPointer( - get_u7_at(data, 1)?, - get_u7_at(data, 2)?, - )); + return Ok(Message::SongPositionPointer(get_u14(data)?)); } SONG_SELECT => { return Ok(Message::SongSelect(get_u7_at(data, 1)?)); @@ -252,11 +256,7 @@ impl TryFrom<&[u8]> for Message { )), PROGRAM_MASK => Ok(Message::ProgramChange(channel, get_u7_at(data, 1)?)), CHANNEL_AFTERTOUCH_MASK => Ok(Message::ChannelAftertouch(channel, get_u7_at(data, 1)?)), - PITCH_BEND_MASK => Ok(Message::PitchWheelChange( - channel, - get_u7_at(data, 1)?, - get_u7_at(data, 2)?, - )), + PITCH_BEND_MASK => Ok(Message::PitchWheelChange(channel, get_u14(data)?)), CONTROL_CHANGE_MASK => Ok(Message::ControlChange( channel, ControlFunction(get_u7_at(data, 1)?), @@ -309,12 +309,12 @@ impl Message { Self::NoteOn(_, _, _) => CodeIndexNumber::NoteOn, Self::NoteOff(_, _, _) => CodeIndexNumber::NoteOff, Self::ChannelAftertouch(_, _) => CodeIndexNumber::ChannelPressure, - Self::PitchWheelChange(_, _, _) => CodeIndexNumber::PitchBendChange, + Self::PitchWheelChange(_, _) => CodeIndexNumber::PitchBendChange, Self::PolyphonicAftertouch(_, _, _) => CodeIndexNumber::PolyKeyPress, Self::ProgramChange(_, _) => CodeIndexNumber::ProgramChange, Self::ControlChange(_, _, _) => CodeIndexNumber::ControlChange, Self::MtcQuarterFrame(_) => CodeIndexNumber::SystemCommon2Bytes, - Self::SongPositionPointer(_, _) => CodeIndexNumber::SystemCommon3Bytes, + Self::SongPositionPointer(_) => CodeIndexNumber::SystemCommon3Bytes, Self::SongSelect(_) => CodeIndexNumber::SystemCommon2Bytes, Self::TuneRequest => CodeIndexNumber::SystemCommon1Byte, Self::TimingClock => CodeIndexNumber::SingleByte, @@ -341,6 +341,12 @@ fn get_u7_at(data: &[u8], index: usize) -> Result { Ok(U7::from_clamped(data_byte)) } +fn get_u14(data: &[u8]) -> Result { + let lsb = get_byte_at_position(data, 1)?; + let msb = get_byte_at_position(data, 2)?; + Ok(U14::from_clamped(((msb as u16) << 7) | (lsb as u16))) +} + fn get_byte_at_position(data: &[u8], index: usize) -> Result { match data.get(index) { Some(byte) => Ok(*byte), @@ -352,6 +358,7 @@ fn get_byte_at_position(data: &[u8], index: usize) -> Result