Skip to content

Commit 50a287d

Browse files
committed
Use U14 type in pitch wheel and song position pointer messages
1 parent ae3e65b commit 50a287d

File tree

3 files changed

+30
-19
lines changed

3 files changed

+30
-19
lines changed

CHANGELOG.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,15 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
1010
### Added
1111

1212
- `Message` enum variants for *System Common* and *System Realtime* messages.
13-
- `U14` primitive value type.
13+
- `U14` primitive value type used by *Pitch Wheel* and *Song Position Pointer* messages.
1414
- Derive `Debug`, `Clone`, `Eq`, and `PartialEq` for `U4`.
1515
- Derive `Debug`, `Clone`, `Eq`, and `PartialEq` for `InvalidU4`.
1616
- Derive `Debug`, `Clone`, `Eq`, and `PartialEq` for `InvalidU7`.
1717

18+
### Changed
19+
20+
- Changed pitch wheel `Message` variant from `PitchWheelChange(Channel, U7, U7)` to `PitchWheelChange(Channel, U14)`.
21+
1822
## [0.4.0] - 2025-01-03
1923

2024
This release focuses on:

src/message/data/u14.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use crate::message::data::{FromClamped, FromOverFlow};
44

55
/// A primitive value that can be from 0-0x4000
66
#[derive(Debug, Clone, Eq, PartialEq)]
7-
pub struct U14(u16);
7+
pub struct U14(pub(crate) u16);
88

99
/// Error representing that this value is not a valid u14
1010
#[derive(Debug, Clone, Eq, PartialEq)]

src/message/mod.rs

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ pub mod raw;
88

99
use crate::message::channel::Channel;
1010
use crate::message::control_function::ControlFunction;
11+
use crate::message::data::u14::U14;
1112
use crate::message::data::u7::U7;
1213
use crate::message::data::FromClamped;
1314
use crate::message::notes::Note;
@@ -36,13 +37,13 @@ pub enum Message {
3637
/// Channel aftertouch message.
3738
ChannelAftertouch(Channel, U7),
3839
/// Pitchwheel message.
39-
PitchWheelChange(Channel, U7, U7),
40+
PitchWheelChange(Channel, U14),
4041
/// Control Change (CC) message.
4142
ControlChange(Channel, ControlFunction, U7),
4243
/// MTC Quarter Frame message.
4344
MtcQuarterFrame(U7),
4445
/// Song Position Pointer message.
45-
SongPositionPointer(U7, U7),
46+
SongPositionPointer(U14),
4647
/// Song Select message.
4748
SongSelect(U7),
4849
/// Tune Request message.
@@ -111,7 +112,10 @@ impl From<Message> for Raw {
111112
let status = CHANNEL_AFTERTOUCH_MASK | u8::from(chan);
112113
Raw { status, payload }
113114
}
114-
Message::PitchWheelChange(chan, lsb, msb) => {
115+
Message::PitchWheelChange(chan, value) => {
116+
let value = u16::from(value);
117+
let lsb = U7::try_from((value & 0x7F) as u8).unwrap();
118+
let msb = U7::try_from(((value >> 7) & 0x7F) as u8).unwrap();
115119
let payload = Payload::DoubleByte(lsb, msb);
116120
let status = PITCH_BEND_MASK | u8::from(chan);
117121
Raw { status, payload }
@@ -126,7 +130,10 @@ impl From<Message> for Raw {
126130
let status = MTC_QUARTER_FRAME;
127131
Raw { status, payload }
128132
}
129-
Message::SongPositionPointer(lsb, msb) => {
133+
Message::SongPositionPointer(value) => {
134+
let value = u16::from(value);
135+
let lsb = U7::try_from((value & 0x7F) as u8).unwrap();
136+
let msb = U7::try_from(((value >> 7) & 0x7F) as u8).unwrap();
130137
let payload = Payload::DoubleByte(lsb, msb);
131138
let status = SONG_POSITION_POINTER;
132139
Raw { status, payload }
@@ -194,10 +201,7 @@ impl TryFrom<&[u8]> for Message {
194201
return Ok(Message::MtcQuarterFrame(get_u7_at(data, 1)?));
195202
}
196203
SONG_POSITION_POINTER => {
197-
return Ok(Message::SongPositionPointer(
198-
get_u7_at(data, 1)?,
199-
get_u7_at(data, 2)?,
200-
));
204+
return Ok(Message::SongPositionPointer(get_u14(data)?));
201205
}
202206
SONG_SELECT => {
203207
return Ok(Message::SongSelect(get_u7_at(data, 1)?));
@@ -252,11 +256,7 @@ impl TryFrom<&[u8]> for Message {
252256
)),
253257
PROGRAM_MASK => Ok(Message::ProgramChange(channel, get_u7_at(data, 1)?)),
254258
CHANNEL_AFTERTOUCH_MASK => Ok(Message::ChannelAftertouch(channel, get_u7_at(data, 1)?)),
255-
PITCH_BEND_MASK => Ok(Message::PitchWheelChange(
256-
channel,
257-
get_u7_at(data, 1)?,
258-
get_u7_at(data, 2)?,
259-
)),
259+
PITCH_BEND_MASK => Ok(Message::PitchWheelChange(channel, get_u14(data)?)),
260260
CONTROL_CHANGE_MASK => Ok(Message::ControlChange(
261261
channel,
262262
ControlFunction(get_u7_at(data, 1)?),
@@ -309,12 +309,12 @@ impl Message {
309309
Self::NoteOn(_, _, _) => CodeIndexNumber::NoteOn,
310310
Self::NoteOff(_, _, _) => CodeIndexNumber::NoteOff,
311311
Self::ChannelAftertouch(_, _) => CodeIndexNumber::ChannelPressure,
312-
Self::PitchWheelChange(_, _, _) => CodeIndexNumber::PitchBendChange,
312+
Self::PitchWheelChange(_, _) => CodeIndexNumber::PitchBendChange,
313313
Self::PolyphonicAftertouch(_, _, _) => CodeIndexNumber::PolyKeyPress,
314314
Self::ProgramChange(_, _) => CodeIndexNumber::ProgramChange,
315315
Self::ControlChange(_, _, _) => CodeIndexNumber::ControlChange,
316316
Self::MtcQuarterFrame(_) => CodeIndexNumber::SystemCommon2Bytes,
317-
Self::SongPositionPointer(_, _) => CodeIndexNumber::SystemCommon3Bytes,
317+
Self::SongPositionPointer(_) => CodeIndexNumber::SystemCommon3Bytes,
318318
Self::SongSelect(_) => CodeIndexNumber::SystemCommon2Bytes,
319319
Self::TuneRequest => CodeIndexNumber::SystemCommon1Byte,
320320
Self::TimingClock => CodeIndexNumber::SingleByte,
@@ -341,6 +341,12 @@ fn get_u7_at(data: &[u8], index: usize) -> Result<U7, UsbMidiEventPacketError> {
341341
Ok(U7::from_clamped(data_byte))
342342
}
343343

344+
fn get_u14(data: &[u8]) -> Result<U14, UsbMidiEventPacketError> {
345+
let lsb = get_byte_at_position(data, 1)?;
346+
let msb = get_byte_at_position(data, 2)?;
347+
Ok(U14::from_clamped(((msb as u16) << 7) | (lsb as u16)))
348+
}
349+
344350
fn get_byte_at_position(data: &[u8], index: usize) -> Result<u8, UsbMidiEventPacketError> {
345351
match data.get(index) {
346352
Some(byte) => Ok(*byte),
@@ -352,6 +358,7 @@ fn get_byte_at_position(data: &[u8], index: usize) -> Result<u8, UsbMidiEventPac
352358
mod tests {
353359
use crate::message::channel::Channel::{Channel1, Channel2};
354360
use crate::message::control_function::ControlFunction;
361+
use crate::message::data::u14::U14;
355362
use crate::message::data::u7::U7;
356363
use crate::message::notes::Note;
357364
use crate::message::Message;
@@ -377,10 +384,10 @@ mod tests {
377384
polyphonic_aftertouch: ([10, 160, 36, 64], Message::PolyphonicAftertouch(Channel1, Note::C2, U7(64)).into_packet(Cable0)),
378385
program_change: ([28, 192, 127, 0], Message::ProgramChange(Channel1, U7(127)).into_packet(Cable1)),
379386
channel_aftertouch: ([13, 208, 127, 0], Message::ChannelAftertouch(Channel1, U7(127)).into_packet(Cable0)),
380-
pitch_wheel: ([14, 224, 64, 32], Message::PitchWheelChange(Channel1, U7(64), U7(32)).into_packet(Cable0)),
387+
pitch_wheel: ([14, 224, 64, 32], Message::PitchWheelChange(Channel1, U14(4160)).into_packet(Cable0)),
381388
control_change: ([11, 177, 1, 32], Message::ControlChange(Channel2, ControlFunction::MOD_WHEEL_1, U7(32)).into_packet(Cable0)),
382389
mtc_quarter_frame: ([0x02, 0xF1, 12, 0], Message::MtcQuarterFrame(U7(12)).into_packet(Cable0)),
383-
song_position_pointer: ([0x03, 0xF2, 38, 75], Message::SongPositionPointer(U7(38), U7(75)).into_packet(Cable0)),
390+
song_position_pointer: ([0x03, 0xF2, 38, 75], Message::SongPositionPointer(U14(9638)).into_packet(Cable0)),
384391
song_select: ([0x02, 0xF3, 4, 0], Message::SongSelect(U7(4)).into_packet(Cable0)),
385392
tune_request: ([0x05, 0xF6, 0, 0], Message::TuneRequest.into_packet(Cable0)),
386393
timing_clock: ([0x0F, 0xF8, 0, 0], Message::TimingClock.into_packet(Cable0)),

0 commit comments

Comments
 (0)