1use crate::{
2 io::WriteSimple,
3 message::{ChannelVoiceMessage, Message, RealTimeMessage, SystemCommonMessage},
4 status::{ChannelStatus, ChannelVoiceStatus, RequiredDataBytes, SystemCommonStatus},
5};
6
7pub struct Encoder<W> {
9 writer: W,
10
11 running_status: Option<ChannelVoiceStatus>,
12}
13
14impl<W> Encoder<W>
15where
16 W: WriteSimple,
17{
18 pub fn new(writer: W) -> Encoder<W> {
19 Encoder {
20 writer,
21 running_status: None,
22 }
23 }
24
25 pub fn write_message(&mut self, message: Message) -> Result<(), W::Error> {
26 let (maybe_status, data_size, data) = match message {
27 Message::ChannelVoice { channel, message } => {
28 let (status, data) = deconstruct_channel_voice_message(channel, message);
29
30 let new_running_status = Some(status);
31
32 let maybe_status = if new_running_status == self.running_status {
33 None
34 } else {
35 Some(status.into())
36 };
37
38 self.running_status = new_running_status;
39
40 (maybe_status, status.status.required_data_bytes(), data)
41 }
42 Message::SystemCommon(message) => {
43 let (status, data) = deconstruct_system_common_message(message);
44 (Some(status.into()), status.required_data_bytes(), data)
45 }
46 Message::RealTime(message) => {
47 let status_byte = encode_real_time(message);
48
49 return self.writer.write_all_simple(&[status_byte]);
50 }
51 Message::SystemExclusive => return self.writer.write_all_simple(&[0b1111_0000]),
52 };
53
54 let data = [data[0] & DATA_MASK, data[1] & DATA_MASK];
55
56 match (maybe_status, data_size) {
57 (None, RequiredDataBytes::D0) => Ok(()),
58 (None, RequiredDataBytes::D1) => self.writer.write_all_simple(&[data[0]]),
59 (None, RequiredDataBytes::D2) => self.writer.write_all_simple(&[data[0], data[1]]),
60 (Some(status_byte), RequiredDataBytes::D0) => {
61 self.writer.write_all_simple(&[status_byte])
62 }
63 (Some(status_byte), RequiredDataBytes::D1) => {
64 self.writer.write_all_simple(&[status_byte, data[0]])
65 }
66 (Some(status_byte), RequiredDataBytes::D2) => {
67 self.writer
68 .write_all_simple(&[status_byte, data[0], data[1]])
69 }
70 }
71 }
72
73 pub fn write_sysex(&mut self, data: impl Iterator<Item = u8>) -> Result<(), W::Error> {
74 self.write_message(Message::SystemExclusive)?;
75
76 for byte in data {
77 self.writer.write_all_simple(&[byte & DATA_MASK])?;
78 }
79
80 self.write_message(Message::SystemCommon(SystemCommonMessage::EOX))?;
81
82 Ok(())
83 }
84}
85
86const DATA_MASK: u8 = 0b0111_1111;
87
88fn deconstruct_channel_voice_message(
89 channel: u8,
90 message: ChannelVoiceMessage,
91) -> (ChannelVoiceStatus, [u8; 2]) {
92 let (status, data) = match message {
93 ChannelVoiceMessage::NoteOff { note, velocity } => {
94 (ChannelStatus::NoteOff, [note, velocity])
95 }
96 ChannelVoiceMessage::NoteOn { note, velocity } => (ChannelStatus::NoteOn, [note, velocity]),
97 ChannelVoiceMessage::PolyphonicPressure { note, pressure } => {
98 (ChannelStatus::PolyphonicPressure, [note, pressure])
99 }
100 ChannelVoiceMessage::ControlChange { control, value } => {
101 (ChannelStatus::ControlChange, [control, value])
102 }
103 ChannelVoiceMessage::ProgramChange { program } => {
104 (ChannelStatus::ProgramChange, [program, 0])
105 }
106 ChannelVoiceMessage::ChannelPressure { pressure } => {
107 (ChannelStatus::ChannelPressure, [pressure, 0])
108 }
109 ChannelVoiceMessage::PitchBend { pitch_bend } => (
110 ChannelStatus::PitchBend,
111 [pitch_bend as u8, (pitch_bend >> 7) as u8],
112 ),
113 };
114
115 let status = ChannelVoiceStatus { status, channel };
116
117 (status, data)
118}
119
120fn deconstruct_system_common_message(
121 message: SystemCommonMessage,
122) -> (SystemCommonStatus, [u8; 2]) {
123 match message {
124 SystemCommonMessage::MTCQuarterFrame { data } => {
125 (SystemCommonStatus::MTCQuarterFrame, [data, 0])
126 }
127 SystemCommonMessage::SongPositionPointer { low, high } => {
128 (SystemCommonStatus::SongPositionPointer, [low, high])
129 }
130 SystemCommonMessage::SongSelect { song } => (SystemCommonStatus::SongSelect, [song, 0]),
131 SystemCommonMessage::Undefined1 => (SystemCommonStatus::Undefined1, [0, 0]),
132 SystemCommonMessage::Undefined2 => (SystemCommonStatus::Undefined2, [0, 0]),
133 SystemCommonMessage::TuneRequest => (SystemCommonStatus::TuneRequest, [0, 0]),
134 SystemCommonMessage::EOX => (SystemCommonStatus::EOX, [0, 0]),
135 }
136}
137
138fn encode_real_time(real_time: RealTimeMessage) -> u8 {
139 match real_time {
140 RealTimeMessage::TimingClock => 0b1111_1000,
141 RealTimeMessage::Undefined1 => 0b1111_1001,
142 RealTimeMessage::Start => 0b1111_1010,
143 RealTimeMessage::Continue => 0b1111_1011,
144 RealTimeMessage::Stop => 0b1111_1100,
145 RealTimeMessage::Undefined2 => 0b1111_1101,
146 RealTimeMessage::ActiveSensing => 0b1111_1110,
147 RealTimeMessage::SystemReset => 0b1111_1111,
148 }
149}