Skip to main content

midi2/flex_data/
set_key_signature.rs

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/// MIDI 2.0 Flex Data Set Key Signature Message
10///
11/// See the [module docs](crate::flex_data) for more info.
12#[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    /// Default is SharpsFlats::Sharps(0)
43    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}