1use crate::{
2 detail::{common_properties, schema, BitOps},
3 flex_data::{self, UMP_MESSAGE_TYPE},
4 ux::{u3, u4},
5};
6
7const STATUS: u8 = 0x5;
8
9#[midi2_proc::generate_message(Via(crate::flex_data::FlexData), FixedSize, MinSizeUmp(4))]
13struct SetKeySignature {
14 #[property(common_properties::UmpMessageTypeProperty<UMP_MESSAGE_TYPE>)]
15 ump_type: (),
16 #[property(common_properties::GroupProperty)]
17 group: crate::ux::u4,
18 #[property(flex_data::OptionalChannelProperty)]
19 optional_channel: Option<crate::ux::u4>,
20 #[property(flex_data::FormatProperty<{flex_data::COMPLETE_FORMAT}>)]
21 format: (),
22 #[property(flex_data::BankProperty<{flex_data::SETUP_AND_PERFORMANCE_BANK}>)]
23 bank: (),
24 #[property(flex_data::StatusProperty<{STATUS}>)]
25 status: (),
26 #[property(flex_data::tonic::TonicProperty<schema::Ump<0x0, 0x0F00_0000, 0x0, 0x0>>)]
27 tonic: flex_data::tonic::Tonic,
28 #[property(SharpsFlatsProperty)]
29 sharps_flats: SharpsFlats,
30}
31
32impl<B: crate::buffer::Ump> flex_data::FlexDataMessage<B> for SetKeySignature<B> {}
33
34#[derive(Debug, Clone, Copy, PartialEq, Eq)]
35pub enum SharpsFlats {
36 Flats(u3),
37 Sharps(u3),
38 NonStandard,
39}
40
41impl core::default::Default for SharpsFlats {
42 fn default() -> Self {
44 SharpsFlats::Sharps(ux::u3::default())
45 }
46}
47
48struct SharpsFlatsProperty;
49
50impl<B: crate::buffer::Ump> crate::detail::property::Property<B> for SharpsFlatsProperty {
51 type Type = SharpsFlats;
52}
53
54impl<'a, B: crate::buffer::Ump> crate::detail::property::ReadProperty<'a, B>
55 for SharpsFlatsProperty
56{
57 fn read(buffer: &'a B) -> Self::Type {
58 use SharpsFlats::*;
59 match u8::from(buffer.buffer()[1].nibble(0)) {
60 v @ 0x0..=0x7 => Sharps(u3::new(v)),
61 v @ 0x9..=0xF => Flats(u3::new(!(v - 1) & 0b0111)),
62 0x8 => NonStandard,
63 _ => unreachable!(),
64 }
65 }
66 fn validate(_buffer: &B) -> Result<(), crate::error::InvalidData> {
67 Ok(())
68 }
69}
70
71impl<B: crate::buffer::Ump + crate::buffer::BufferMut> crate::detail::property::WriteProperty<B>
72 for SharpsFlatsProperty
73{
74 fn write(buffer: &mut B, v: Self::Type) {
75 buffer.buffer_mut()[1].set_nibble(
76 0,
77 match v {
78 SharpsFlats::Sharps(v) => u4::from(v),
79 SharpsFlats::Flats(v) => u4::new((!u8::from(v) & 0b0000_1111) + 1),
80 SharpsFlats::NonStandard => u4::new(0x8),
81 },
82 );
83 }
84 fn validate(_: &Self::Type) -> Result<(), crate::error::InvalidData> {
85 Ok(())
86 }
87 fn default() -> Self::Type {
88 Default::default()
89 }
90}
91
92#[cfg(test)]
93mod tests {
94 use super::*;
95 use crate::traits::Grouped;
96 use pretty_assertions::assert_eq;
97
98 #[test]
99 fn setters() {
100 let mut message = SetKeySignature::<[u32; 4]>::new();
101 message.set_group(u4::new(0x4));
102 message.set_tonic(flex_data::tonic::Tonic::D);
103 message.set_sharps_flats(SharpsFlats::Sharps(u3::new(5)));
104 assert_eq!(
105 message,
106 SetKeySignature([0xD410_0005, 0x5400_0000, 0x0, 0x0,]),
107 );
108 }
109
110 #[test]
111 fn set_flats() {
112 let mut message = SetKeySignature::<[u32; 4]>::new();
113 message.set_group(u4::new(0x4));
114 message.set_tonic(flex_data::tonic::Tonic::D);
115 message.set_sharps_flats(SharpsFlats::Flats(u3::new(5)));
116 assert_eq!(
117 message,
118 SetKeySignature([0xD410_0005, 0xB400_0000, 0x0, 0x0,]),
119 );
120 }
121
122 #[test]
123 fn builder_non_standard() {
124 let mut message = SetKeySignature::<[u32; 4]>::new();
125 message.set_group(u4::new(0x4));
126 message.set_tonic(flex_data::tonic::Tonic::NonStandard);
127 message.set_sharps_flats(SharpsFlats::NonStandard);
128 assert_eq!(
129 message,
130 SetKeySignature([0xD410_0005, 0x8000_0000, 0x0, 0x0,]),
131 );
132 }
133
134 #[test]
135 fn builder_channel() {
136 let mut message = SetKeySignature::<[u32; 4]>::new();
137 message.set_group(u4::new(0x4));
138 message.set_tonic(flex_data::tonic::Tonic::NonStandard);
139 message.set_sharps_flats(SharpsFlats::NonStandard);
140 message.set_optional_channel(Some(u4::new(0xD)));
141 assert_eq!(
142 message,
143 SetKeySignature([0xD40D_0005, 0x8000_0000, 0x0, 0x0,]),
144 );
145 }
146
147 #[test]
148 fn tonic() {
149 assert_eq!(
150 SetKeySignature::try_from(&[0xD410_0005, 0x5400_0000, 0x0, 0x0][..])
151 .unwrap()
152 .tonic(),
153 flex_data::tonic::Tonic::D,
154 );
155 }
156
157 #[test]
158 fn sharps_flats() {
159 assert_eq!(
160 SetKeySignature::try_from(&[0xD410_0005, 0x5400_0000, 0x0, 0x0][..])
161 .unwrap()
162 .sharps_flats(),
163 SharpsFlats::Sharps(u3::new(5)),
164 );
165 }
166
167 #[test]
168 fn sharps_flats_with_flats() {
169 assert_eq!(
170 SetKeySignature::try_from(&[0xD410_0005, 0xB400_0000, 0x0, 0x0][..])
171 .unwrap()
172 .sharps_flats(),
173 SharpsFlats::Flats(u3::new(5)),
174 );
175 }
176
177 #[test]
178 fn sharps_flats_non_standard() {
179 assert_eq!(
180 SetKeySignature::try_from(&[0xD410_0005, 0x8000_0000, 0x0, 0x0][..])
181 .unwrap()
182 .sharps_flats(),
183 SharpsFlats::NonStandard,
184 );
185 }
186
187 #[test]
188 fn channel() {
189 assert_eq!(
190 SetKeySignature::try_from(&[0xD40D_0005, 0x8000_0000, 0x0, 0x0][..])
191 .unwrap()
192 .optional_channel(),
193 Some(u4::new(0xD)),
194 );
195 }
196
197 #[test]
198 fn no_channel() {
199 assert_eq!(
200 SetKeySignature::try_from(&[0xD410_0005, 0x8000_0000, 0x0, 0x0][..])
201 .unwrap()
202 .optional_channel(),
203 None,
204 );
205 }
206}