midi2/
flex_data.rs

1#![doc = include_str!("flex_data/README.md")]
2
3use crate::{
4    buffer::{BufferMut, Ump},
5    detail::{
6        property::{Property, ReadProperty, WriteProperty},
7        BitOps,
8    },
9};
10
11mod packet;
12mod text;
13
14mod set_chord_name;
15mod set_key_signature;
16mod set_metronome;
17mod set_tempo;
18mod set_time_signature;
19mod tonic;
20mod unknown_metadata_text;
21mod project_name {
22    use crate::{detail::common_properties, flex_data};
23
24    const BANK: u8 = super::METADATA_TEXT_BANK;
25    const STATUS: u8 = 0x1;
26
27    /// MIDI 2.0 Project Name Message
28    ///
29    /// See the [module docs](crate::flex_data) for more info.
30    #[midi2_proc::generate_message(Via(crate::flex_data::FlexData), MinSizeUmp(4))]
31    struct ProjectName {
32        #[property(common_properties::UmpMessageTypeProperty<{flex_data::UMP_MESSAGE_TYPE}>)]
33        ump_type: (),
34        #[property(flex_data::GroupProperty)]
35        group: crate::ux::u4,
36        #[property(flex_data::OptionalChannelProperty)]
37        optional_channel: Option<crate::ux::u4>,
38        #[property(flex_data::BankProperty<BANK>)]
39        bank: (),
40        #[property(flex_data::StatusProperty<{STATUS}>)]
41        status: (),
42        #[property(flex_data::ConsistentFormatsProperty)]
43        #[readonly]
44        consisten_formats: (),
45        #[property(flex_data::text::TextWriteStrProperty)]
46        #[writeonly]
47        #[resize]
48        text: &str,
49        #[property(flex_data::text::TextReadBytesProperty)]
50        #[readonly]
51        text_bytes: flex_data::text::TextBytesIterator,
52        #[property(flex_data::text::TextReadStringProperty)]
53        #[readonly]
54        #[std]
55        text: std::string::String,
56    }
57
58    impl<B: crate::buffer::Ump> crate::traits::Size<B> for ProjectName<B> {
59        fn size(&self) -> usize {
60            flex_data::flex_data_dyn_size(&self.0)
61        }
62    }
63    impl<B: crate::buffer::Ump> flex_data::FlexDataMessage<B> for ProjectName<B> {}
64}
65mod composition_name {
66    use crate::{detail::common_properties, flex_data};
67
68    const BANK: u8 = super::METADATA_TEXT_BANK;
69    const STATUS: u8 = 0x2;
70
71    /// MIDI 2.0 Composition Name Message
72    ///
73    /// See the [module docs](crate::flex_data) for more info.
74    #[midi2_proc::generate_message(Via(crate::flex_data::FlexData), MinSizeUmp(4))]
75    struct CompositionName {
76        #[property(common_properties::UmpMessageTypeProperty<{flex_data::UMP_MESSAGE_TYPE}>)]
77        ump_type: (),
78        #[property(flex_data::GroupProperty)]
79        group: crate::ux::u4,
80        #[property(flex_data::OptionalChannelProperty)]
81        optional_channel: Option<crate::ux::u4>,
82        #[property(flex_data::BankProperty<BANK>)]
83        bank: (),
84        #[property(flex_data::StatusProperty<{STATUS}>)]
85        status: (),
86        #[property(flex_data::ConsistentFormatsProperty)]
87        #[readonly]
88        consisten_formats: (),
89        #[property(flex_data::text::TextWriteStrProperty)]
90        #[writeonly]
91        #[resize]
92        text: &str,
93        #[property(flex_data::text::TextReadBytesProperty)]
94        #[readonly]
95        text_bytes: flex_data::text::TextBytesIterator,
96        #[property(flex_data::text::TextReadStringProperty)]
97        #[readonly]
98        #[std]
99        text: std::string::String,
100    }
101
102    impl<B: crate::buffer::Ump> crate::traits::Size<B> for CompositionName<B> {
103        fn size(&self) -> usize {
104            flex_data::flex_data_dyn_size(&self.0)
105        }
106    }
107    impl<B: crate::buffer::Ump> flex_data::FlexDataMessage<B> for CompositionName<B> {}
108}
109mod midi_clip_name {
110    use crate::{detail::common_properties, flex_data};
111
112    const BANK: u8 = super::METADATA_TEXT_BANK;
113    const STATUS: u8 = 0x3;
114
115    /// MIDI 2.0 Midi Clip Name Message
116    ///
117    /// See the [module docs](crate::flex_data) for more info.
118    #[midi2_proc::generate_message(Via(crate::flex_data::FlexData), MinSizeUmp(4))]
119    struct MidiClipName {
120        #[property(common_properties::UmpMessageTypeProperty<{flex_data::UMP_MESSAGE_TYPE}>)]
121        ump_type: (),
122        #[property(flex_data::GroupProperty)]
123        group: crate::ux::u4,
124        #[property(flex_data::OptionalChannelProperty)]
125        optional_channel: Option<crate::ux::u4>,
126        #[property(flex_data::BankProperty<BANK>)]
127        bank: (),
128        #[property(flex_data::StatusProperty<{STATUS}>)]
129        status: (),
130        #[property(flex_data::ConsistentFormatsProperty)]
131        #[readonly]
132        consisten_formats: (),
133        #[property(flex_data::text::TextWriteStrProperty)]
134        #[writeonly]
135        #[resize]
136        text: &str,
137        #[property(flex_data::text::TextReadBytesProperty)]
138        #[readonly]
139        text_bytes: flex_data::text::TextBytesIterator,
140        #[property(flex_data::text::TextReadStringProperty)]
141        #[readonly]
142        #[std]
143        text: std::string::String,
144    }
145
146    impl<B: crate::buffer::Ump> crate::traits::Size<B> for MidiClipName<B> {
147        fn size(&self) -> usize {
148            flex_data::flex_data_dyn_size(&self.0)
149        }
150    }
151    impl<B: crate::buffer::Ump> flex_data::FlexDataMessage<B> for MidiClipName<B> {}
152}
153mod copyright_notice {
154    use crate::{detail::common_properties, flex_data};
155
156    const BANK: u8 = super::METADATA_TEXT_BANK;
157    const STATUS: u8 = 0x4;
158
159    /// MIDI 2.0 Copyright Notice Message
160    ///
161    /// See the [module docs](crate::flex_data) for more info.
162    #[midi2_proc::generate_message(Via(crate::flex_data::FlexData), MinSizeUmp(4))]
163    struct CopyrightNotice {
164        #[property(common_properties::UmpMessageTypeProperty<{flex_data::UMP_MESSAGE_TYPE}>)]
165        ump_type: (),
166        #[property(flex_data::GroupProperty)]
167        group: crate::ux::u4,
168        #[property(flex_data::OptionalChannelProperty)]
169        optional_channel: Option<crate::ux::u4>,
170        #[property(flex_data::BankProperty<BANK>)]
171        bank: (),
172        #[property(flex_data::StatusProperty<{STATUS}>)]
173        status: (),
174        #[property(flex_data::ConsistentFormatsProperty)]
175        #[readonly]
176        consisten_formats: (),
177        #[property(flex_data::text::TextWriteStrProperty)]
178        #[writeonly]
179        #[resize]
180        text: &str,
181        #[property(flex_data::text::TextReadBytesProperty)]
182        #[readonly]
183        text_bytes: flex_data::text::TextBytesIterator,
184        #[property(flex_data::text::TextReadStringProperty)]
185        #[readonly]
186        #[std]
187        text: std::string::String,
188    }
189
190    impl<B: crate::buffer::Ump> crate::traits::Size<B> for CopyrightNotice<B> {
191        fn size(&self) -> usize {
192            flex_data::flex_data_dyn_size(&self.0)
193        }
194    }
195    impl<B: crate::buffer::Ump> flex_data::FlexDataMessage<B> for CopyrightNotice<B> {}
196}
197mod composer_name {
198    use crate::{detail::common_properties, flex_data};
199
200    const BANK: u8 = super::METADATA_TEXT_BANK;
201    const STATUS: u8 = 0x5;
202
203    /// MIDI 2.0 Composer Name Message
204    ///
205    /// See the [module docs](crate::flex_data) for more info.
206    #[midi2_proc::generate_message(Via(crate::flex_data::FlexData), MinSizeUmp(4))]
207    struct ComposerName {
208        #[property(common_properties::UmpMessageTypeProperty<{flex_data::UMP_MESSAGE_TYPE}>)]
209        ump_type: (),
210        #[property(flex_data::GroupProperty)]
211        group: crate::ux::u4,
212        #[property(flex_data::OptionalChannelProperty)]
213        optional_channel: Option<crate::ux::u4>,
214        #[property(flex_data::BankProperty<BANK>)]
215        bank: (),
216        #[property(flex_data::StatusProperty<{STATUS}>)]
217        status: (),
218        #[property(flex_data::ConsistentFormatsProperty)]
219        #[readonly]
220        consisten_formats: (),
221        #[property(flex_data::text::TextWriteStrProperty)]
222        #[writeonly]
223        #[resize]
224        name: &str,
225        #[property(flex_data::text::TextReadBytesProperty)]
226        #[readonly]
227        name_bytes: flex_data::text::TextBytesIterator,
228        #[property(flex_data::text::TextReadStringProperty)]
229        #[readonly]
230        #[std]
231        name: std::string::String,
232    }
233
234    impl<B: crate::buffer::Ump> crate::traits::Size<B> for ComposerName<B> {
235        fn size(&self) -> usize {
236            flex_data::flex_data_dyn_size(&self.0)
237        }
238    }
239    impl<B: crate::buffer::Ump> flex_data::FlexDataMessage<B> for ComposerName<B> {}
240}
241mod lyricist_name {
242    use crate::{detail::common_properties, flex_data};
243
244    const BANK: u8 = super::METADATA_TEXT_BANK;
245    const STATUS: u8 = 0x6;
246
247    /// MIDI 2.0 Lyricist Name Message
248    ///
249    /// See the [module docs](crate::flex_data) for more info.
250    #[midi2_proc::generate_message(Via(crate::flex_data::FlexData), MinSizeUmp(4))]
251    struct LyricistName {
252        #[property(common_properties::UmpMessageTypeProperty<{flex_data::UMP_MESSAGE_TYPE}>)]
253        ump_type: (),
254        #[property(flex_data::GroupProperty)]
255        group: crate::ux::u4,
256        #[property(flex_data::OptionalChannelProperty)]
257        optional_channel: Option<crate::ux::u4>,
258        #[property(flex_data::BankProperty<BANK>)]
259        bank: (),
260        #[property(flex_data::StatusProperty<{STATUS}>)]
261        status: (),
262        #[property(flex_data::ConsistentFormatsProperty)]
263        #[readonly]
264        consisten_formats: (),
265        #[property(flex_data::text::TextWriteStrProperty)]
266        #[writeonly]
267        #[resize]
268        text: &str,
269        #[property(flex_data::text::TextReadBytesProperty)]
270        #[readonly]
271        text_bytes: flex_data::text::TextBytesIterator,
272        #[property(flex_data::text::TextReadStringProperty)]
273        #[readonly]
274        #[std]
275        text: std::string::String,
276    }
277
278    impl<B: crate::buffer::Ump> crate::traits::Size<B> for LyricistName<B> {
279        fn size(&self) -> usize {
280            flex_data::flex_data_dyn_size(&self.0)
281        }
282    }
283    impl<B: crate::buffer::Ump> flex_data::FlexDataMessage<B> for LyricistName<B> {}
284}
285mod arranger_name {
286    use crate::{detail::common_properties, flex_data};
287
288    const BANK: u8 = super::METADATA_TEXT_BANK;
289    const STATUS: u8 = 0x7;
290
291    /// MIDI 2.0 Arranger Name Message
292    ///
293    /// See the [module docs](crate::flex_data) for more info.
294    #[midi2_proc::generate_message(Via(crate::flex_data::FlexData), MinSizeUmp(4))]
295    struct ArrangerName {
296        #[property(common_properties::UmpMessageTypeProperty<{flex_data::UMP_MESSAGE_TYPE}>)]
297        ump_type: (),
298        #[property(flex_data::GroupProperty)]
299        group: crate::ux::u4,
300        #[property(flex_data::OptionalChannelProperty)]
301        optional_channel: Option<crate::ux::u4>,
302        #[property(flex_data::BankProperty<BANK>)]
303        bank: (),
304        #[property(flex_data::StatusProperty<{STATUS}>)]
305        status: (),
306        #[property(flex_data::ConsistentFormatsProperty)]
307        #[readonly]
308        consisten_formats: (),
309        #[property(flex_data::text::TextWriteStrProperty)]
310        #[writeonly]
311        #[resize]
312        text: &str,
313        #[property(flex_data::text::TextReadBytesProperty)]
314        #[readonly]
315        text_bytes: flex_data::text::TextBytesIterator,
316        #[property(flex_data::text::TextReadStringProperty)]
317        #[readonly]
318        #[std]
319        text: std::string::String,
320    }
321
322    impl<B: crate::buffer::Ump> crate::traits::Size<B> for ArrangerName<B> {
323        fn size(&self) -> usize {
324            flex_data::flex_data_dyn_size(&self.0)
325        }
326    }
327    impl<B: crate::buffer::Ump> flex_data::FlexDataMessage<B> for ArrangerName<B> {}
328}
329mod publisher_name {
330    use crate::{detail::common_properties, flex_data};
331
332    const BANK: u8 = super::METADATA_TEXT_BANK;
333    const STATUS: u8 = 0x8;
334
335    /// MIDI 2.0 Publisher Name Message
336    ///
337    /// See the [module docs](crate::flex_data) for more info.
338    #[midi2_proc::generate_message(Via(crate::flex_data::FlexData), MinSizeUmp(4))]
339    struct PublisherName {
340        #[property(common_properties::UmpMessageTypeProperty<{flex_data::UMP_MESSAGE_TYPE}>)]
341        ump_type: (),
342        #[property(flex_data::GroupProperty)]
343        group: crate::ux::u4,
344        #[property(flex_data::OptionalChannelProperty)]
345        optional_channel: Option<crate::ux::u4>,
346        #[property(flex_data::BankProperty<BANK>)]
347        bank: (),
348        #[property(flex_data::StatusProperty<{STATUS}>)]
349        status: (),
350        #[property(flex_data::ConsistentFormatsProperty)]
351        #[readonly]
352        consisten_formats: (),
353        #[property(flex_data::text::TextWriteStrProperty)]
354        #[writeonly]
355        #[resize]
356        text: &str,
357        #[property(flex_data::text::TextReadBytesProperty)]
358        #[readonly]
359        text_bytes: flex_data::text::TextBytesIterator,
360        #[property(flex_data::text::TextReadStringProperty)]
361        #[readonly]
362        #[std]
363        text: std::string::String,
364    }
365
366    impl<B: crate::buffer::Ump> crate::traits::Size<B> for PublisherName<B> {
367        fn size(&self) -> usize {
368            flex_data::flex_data_dyn_size(&self.0)
369        }
370    }
371    impl<B: crate::buffer::Ump> flex_data::FlexDataMessage<B> for PublisherName<B> {}
372}
373mod primary_performer_name {
374    use crate::{detail::common_properties, flex_data};
375
376    const BANK: u8 = super::METADATA_TEXT_BANK;
377    const STATUS: u8 = 0x9;
378
379    /// MIDI 2.0 Primary Performer Name Message
380    ///
381    /// See the [module docs](crate::flex_data) for more info.
382    #[midi2_proc::generate_message(Via(crate::flex_data::FlexData), MinSizeUmp(4))]
383    struct PrimaryPerformerName {
384        #[property(common_properties::UmpMessageTypeProperty<{flex_data::UMP_MESSAGE_TYPE}>)]
385        ump_type: (),
386        #[property(flex_data::GroupProperty)]
387        group: crate::ux::u4,
388        #[property(flex_data::OptionalChannelProperty)]
389        optional_channel: Option<crate::ux::u4>,
390        #[property(flex_data::BankProperty<BANK>)]
391        bank: (),
392        #[property(flex_data::StatusProperty<{STATUS}>)]
393        status: (),
394        #[property(flex_data::ConsistentFormatsProperty)]
395        #[readonly]
396        consisten_formats: (),
397        #[property(flex_data::text::TextWriteStrProperty)]
398        #[writeonly]
399        #[resize]
400        text: &str,
401        #[property(flex_data::text::TextReadBytesProperty)]
402        #[readonly]
403        text_bytes: flex_data::text::TextBytesIterator,
404        #[property(flex_data::text::TextReadStringProperty)]
405        #[readonly]
406        #[std]
407        text: std::string::String,
408    }
409
410    impl<B: crate::buffer::Ump> crate::traits::Size<B> for PrimaryPerformerName<B> {
411        fn size(&self) -> usize {
412            flex_data::flex_data_dyn_size(&self.0)
413        }
414    }
415    impl<B: crate::buffer::Ump> flex_data::FlexDataMessage<B> for PrimaryPerformerName<B> {}
416}
417mod accompanying_performer_name {
418    use crate::{detail::common_properties, flex_data};
419
420    const BANK: u8 = super::METADATA_TEXT_BANK;
421    const STATUS: u8 = 0xA;
422
423    /// MIDI 2.0 Accompanying Performer Name Message
424    ///
425    /// See the [module docs](crate::flex_data) for more info.
426    #[midi2_proc::generate_message(Via(crate::flex_data::FlexData), MinSizeUmp(4))]
427    struct AccompanyingPerformerName {
428        #[property(common_properties::UmpMessageTypeProperty<{flex_data::UMP_MESSAGE_TYPE}>)]
429        ump_type: (),
430        #[property(flex_data::GroupProperty)]
431        group: crate::ux::u4,
432        #[property(flex_data::OptionalChannelProperty)]
433        optional_channel: Option<crate::ux::u4>,
434        #[property(flex_data::BankProperty<BANK>)]
435        bank: (),
436        #[property(flex_data::StatusProperty<{STATUS}>)]
437        status: (),
438        #[property(flex_data::ConsistentFormatsProperty)]
439        #[readonly]
440        consisten_formats: (),
441        #[property(flex_data::text::TextWriteStrProperty)]
442        #[writeonly]
443        #[resize]
444        text: &str,
445        #[property(flex_data::text::TextReadBytesProperty)]
446        #[readonly]
447        text_bytes: flex_data::text::TextBytesIterator,
448        #[property(flex_data::text::TextReadStringProperty)]
449        #[readonly]
450        #[std]
451        text: std::string::String,
452    }
453
454    impl<B: crate::buffer::Ump> crate::traits::Size<B> for AccompanyingPerformerName<B> {
455        fn size(&self) -> usize {
456            flex_data::flex_data_dyn_size(&self.0)
457        }
458    }
459    impl<B: crate::buffer::Ump> flex_data::FlexDataMessage<B> for AccompanyingPerformerName<B> {}
460}
461mod recording_date {
462    use crate::{detail::common_properties, flex_data};
463
464    const BANK: u8 = super::METADATA_TEXT_BANK;
465    const STATUS: u8 = 0xB;
466
467    /// MIDI 2.0 Recording Date Message
468    ///
469    /// See the [module docs](crate::flex_data) for more info.
470    #[midi2_proc::generate_message(Via(crate::flex_data::FlexData), MinSizeUmp(4))]
471    struct RecordingDate {
472        #[property(common_properties::UmpMessageTypeProperty<{flex_data::UMP_MESSAGE_TYPE}>)]
473        ump_type: (),
474        #[property(flex_data::GroupProperty)]
475        group: crate::ux::u4,
476        #[property(flex_data::OptionalChannelProperty)]
477        optional_channel: Option<crate::ux::u4>,
478        #[property(flex_data::BankProperty<BANK>)]
479        bank: (),
480        #[property(flex_data::StatusProperty<{STATUS}>)]
481        status: (),
482        #[property(flex_data::ConsistentFormatsProperty)]
483        #[readonly]
484        consisten_formats: (),
485        #[property(flex_data::text::TextWriteStrProperty)]
486        #[writeonly]
487        #[resize]
488        text: &str,
489        #[property(flex_data::text::TextReadBytesProperty)]
490        #[readonly]
491        text_bytes: flex_data::text::TextBytesIterator,
492        #[property(flex_data::text::TextReadStringProperty)]
493        #[readonly]
494        #[std]
495        text: std::string::String,
496    }
497
498    impl<B: crate::buffer::Ump> crate::traits::Size<B> for RecordingDate<B> {
499        fn size(&self) -> usize {
500            flex_data::flex_data_dyn_size(&self.0)
501        }
502    }
503    impl<B: crate::buffer::Ump> flex_data::FlexDataMessage<B> for RecordingDate<B> {}
504}
505mod recording_location {
506    use crate::{detail::common_properties, flex_data};
507
508    const BANK: u8 = super::METADATA_TEXT_BANK;
509    const STATUS: u8 = 0xC;
510
511    /// MIDI 2.0 Recording Location Message
512    ///
513    /// See the [module docs](crate::flex_data) for more info.
514    #[midi2_proc::generate_message(Via(crate::flex_data::FlexData), MinSizeUmp(4))]
515    struct RecordingLocation {
516        #[property(common_properties::UmpMessageTypeProperty<{flex_data::UMP_MESSAGE_TYPE}>)]
517        ump_type: (),
518        #[property(flex_data::GroupProperty)]
519        group: crate::ux::u4,
520        #[property(flex_data::OptionalChannelProperty)]
521        optional_channel: Option<crate::ux::u4>,
522        #[property(flex_data::BankProperty<BANK>)]
523        bank: (),
524        #[property(flex_data::StatusProperty<{STATUS}>)]
525        status: (),
526        #[property(flex_data::ConsistentFormatsProperty)]
527        #[readonly]
528        consisten_formats: (),
529        #[property(flex_data::text::TextWriteStrProperty)]
530        #[writeonly]
531        #[resize]
532        text: &str,
533        #[property(flex_data::text::TextReadBytesProperty)]
534        #[readonly]
535        text_bytes: flex_data::text::TextBytesIterator,
536        #[property(flex_data::text::TextReadStringProperty)]
537        #[readonly]
538        #[std]
539        text: std::string::String,
540    }
541
542    impl<B: crate::buffer::Ump> crate::traits::Size<B> for RecordingLocation<B> {
543        fn size(&self) -> usize {
544            flex_data::flex_data_dyn_size(&self.0)
545        }
546    }
547    impl<B: crate::buffer::Ump> flex_data::FlexDataMessage<B> for RecordingLocation<B> {}
548}
549mod unknown_performance_text {
550    use crate::{detail::common_properties, flex_data};
551
552    const BANK: u8 = super::PERFORMANCE_TEXT_BANK;
553    const STATUS: u8 = 0x0;
554
555    /// MIDI 2.0 Unknown Performance Text Message
556    ///
557    /// See the [module docs](crate::flex_data) for more info.
558    #[midi2_proc::generate_message(Via(crate::flex_data::FlexData), MinSizeUmp(4))]
559    struct UnknownPerformanceText {
560        #[property(common_properties::UmpMessageTypeProperty<{flex_data::UMP_MESSAGE_TYPE}>)]
561        ump_type: (),
562        #[property(flex_data::GroupProperty)]
563        group: crate::ux::u4,
564        #[property(flex_data::OptionalChannelProperty)]
565        optional_channel: Option<crate::ux::u4>,
566        #[property(flex_data::BankProperty<BANK>)]
567        bank: (),
568        #[property(flex_data::StatusProperty<{STATUS}>)]
569        status: (),
570        #[property(flex_data::ConsistentFormatsProperty)]
571        #[readonly]
572        consisten_formats: (),
573        #[property(flex_data::text::TextWriteStrProperty)]
574        #[writeonly]
575        #[resize]
576        text: &str,
577        #[property(flex_data::text::TextReadBytesProperty)]
578        #[readonly]
579        text_bytes: flex_data::text::TextBytesIterator,
580        #[property(flex_data::text::TextReadStringProperty)]
581        #[readonly]
582        #[std]
583        text: std::string::String,
584    }
585
586    impl<B: crate::buffer::Ump> crate::traits::Size<B> for UnknownPerformanceText<B> {
587        fn size(&self) -> usize {
588            flex_data::flex_data_dyn_size(&self.0)
589        }
590    }
591    impl<B: crate::buffer::Ump> flex_data::FlexDataMessage<B> for UnknownPerformanceText<B> {}
592}
593mod lyrics {
594    use crate::{detail::common_properties, flex_data};
595
596    const BANK: u8 = super::PERFORMANCE_TEXT_BANK;
597    const STATUS: u8 = 0x1;
598
599    /// MIDI 2.0 Lyrics Message
600    ///
601    /// See the [module docs](crate::flex_data) for more info.
602    #[midi2_proc::generate_message(Via(crate::flex_data::FlexData), MinSizeUmp(4))]
603    struct Lyrics {
604        #[property(common_properties::UmpMessageTypeProperty<{flex_data::UMP_MESSAGE_TYPE}>)]
605        ump_type: (),
606        #[property(flex_data::GroupProperty)]
607        group: crate::ux::u4,
608        #[property(flex_data::OptionalChannelProperty)]
609        optional_channel: Option<crate::ux::u4>,
610        #[property(flex_data::BankProperty<BANK>)]
611        bank: (),
612        #[property(flex_data::StatusProperty<{STATUS}>)]
613        status: (),
614        #[property(flex_data::ConsistentFormatsProperty)]
615        #[readonly]
616        consisten_formats: (),
617        #[property(flex_data::text::TextWriteStrProperty)]
618        #[writeonly]
619        #[resize]
620        text: &str,
621        #[property(flex_data::text::TextReadBytesProperty)]
622        #[readonly]
623        text_bytes: flex_data::text::TextBytesIterator,
624        #[property(flex_data::text::TextReadStringProperty)]
625        #[readonly]
626        #[std]
627        text: std::string::String,
628    }
629
630    impl<B: crate::buffer::Ump> crate::traits::Size<B> for Lyrics<B> {
631        fn size(&self) -> usize {
632            flex_data::flex_data_dyn_size(&self.0)
633        }
634    }
635    impl<B: crate::buffer::Ump> flex_data::FlexDataMessage<B> for Lyrics<B> {}
636}
637mod lyrics_language {
638    use crate::{detail::common_properties, flex_data};
639
640    const BANK: u8 = super::PERFORMANCE_TEXT_BANK;
641    const STATUS: u8 = 0x2;
642
643    /// MIDI 2.0 Lyrics Language Message
644    ///
645    /// See the [module docs](crate::flex_data) for more info.
646    #[midi2_proc::generate_message(Via(crate::flex_data::FlexData), MinSizeUmp(4))]
647    struct LyricsLanguage {
648        #[property(common_properties::UmpMessageTypeProperty<{flex_data::UMP_MESSAGE_TYPE}>)]
649        ump_type: (),
650        #[property(flex_data::GroupProperty)]
651        group: crate::ux::u4,
652        #[property(flex_data::OptionalChannelProperty)]
653        optional_channel: Option<crate::ux::u4>,
654        #[property(flex_data::BankProperty<BANK>)]
655        bank: (),
656        #[property(flex_data::StatusProperty<{STATUS}>)]
657        status: (),
658        #[property(flex_data::ConsistentFormatsProperty)]
659        #[readonly]
660        consisten_formats: (),
661        #[property(flex_data::text::TextWriteStrProperty)]
662        #[writeonly]
663        #[resize]
664        text: &str,
665        #[property(flex_data::text::TextReadBytesProperty)]
666        #[readonly]
667        text_bytes: flex_data::text::TextBytesIterator,
668        #[property(flex_data::text::TextReadStringProperty)]
669        #[readonly]
670        #[std]
671        text: std::string::String,
672    }
673
674    impl<B: crate::buffer::Ump> crate::traits::Size<B> for LyricsLanguage<B> {
675        fn size(&self) -> usize {
676            flex_data::flex_data_dyn_size(&self.0)
677        }
678    }
679    impl<B: crate::buffer::Ump> flex_data::FlexDataMessage<B> for LyricsLanguage<B> {}
680}
681mod ruby {
682    use crate::{detail::common_properties, flex_data};
683
684    const BANK: u8 = super::PERFORMANCE_TEXT_BANK;
685    const STATUS: u8 = 0x3;
686
687    /// MIDI 2.0 Ruby Message
688    ///
689    /// See the [module docs](crate::flex_data) for more info.
690    #[midi2_proc::generate_message(Via(crate::flex_data::FlexData), MinSizeUmp(4))]
691    struct Ruby {
692        #[property(common_properties::UmpMessageTypeProperty<{flex_data::UMP_MESSAGE_TYPE}>)]
693        ump_type: (),
694        #[property(flex_data::GroupProperty)]
695        group: crate::ux::u4,
696        #[property(flex_data::OptionalChannelProperty)]
697        optional_channel: Option<crate::ux::u4>,
698        #[property(flex_data::BankProperty<BANK>)]
699        bank: (),
700        #[property(flex_data::StatusProperty<{STATUS}>)]
701        status: (),
702        #[property(flex_data::ConsistentFormatsProperty)]
703        #[readonly]
704        consisten_formats: (),
705        #[property(flex_data::text::TextWriteStrProperty)]
706        #[writeonly]
707        #[resize]
708        text: &str,
709        #[property(flex_data::text::TextReadBytesProperty)]
710        #[readonly]
711        text_bytes: flex_data::text::TextBytesIterator,
712        #[property(flex_data::text::TextReadStringProperty)]
713        #[readonly]
714        #[std]
715        text: std::string::String,
716    }
717
718    impl<B: crate::buffer::Ump> crate::traits::Size<B> for Ruby<B> {
719        fn size(&self) -> usize {
720            flex_data::flex_data_dyn_size(&self.0)
721        }
722    }
723    impl<B: crate::buffer::Ump> flex_data::FlexDataMessage<B> for Ruby<B> {}
724}
725mod ruby_language {
726    use crate::{detail::common_properties, flex_data};
727
728    const BANK: u8 = super::PERFORMANCE_TEXT_BANK;
729    const STATUS: u8 = 0x4;
730
731    /// MIDI 2.0 Ruby Language Message
732    ///
733    /// See the [module docs](crate::flex_data) for more info.
734    #[midi2_proc::generate_message(Via(crate::flex_data::FlexData), MinSizeUmp(4))]
735    struct RubyLanguage {
736        #[property(common_properties::UmpMessageTypeProperty<{flex_data::UMP_MESSAGE_TYPE}>)]
737        ump_type: (),
738        #[property(flex_data::GroupProperty)]
739        group: crate::ux::u4,
740        #[property(flex_data::OptionalChannelProperty)]
741        optional_channel: Option<crate::ux::u4>,
742        #[property(flex_data::BankProperty<BANK>)]
743        bank: (),
744        #[property(flex_data::StatusProperty<{STATUS}>)]
745        status: (),
746        #[property(flex_data::ConsistentFormatsProperty)]
747        #[readonly]
748        consisten_formats: (),
749        #[property(flex_data::text::TextWriteStrProperty)]
750        #[writeonly]
751        #[resize]
752        text: &str,
753        #[property(flex_data::text::TextReadBytesProperty)]
754        #[readonly]
755        text_bytes: flex_data::text::TextBytesIterator,
756        #[property(flex_data::text::TextReadStringProperty)]
757        #[readonly]
758        #[std]
759        text: std::string::String,
760    }
761
762    impl<B: crate::buffer::Ump> crate::traits::Size<B> for RubyLanguage<B> {
763        fn size(&self) -> usize {
764            flex_data::flex_data_dyn_size(&self.0)
765        }
766    }
767    impl<B: crate::buffer::Ump> flex_data::FlexDataMessage<B> for RubyLanguage<B> {}
768}
769
770pub use accompanying_performer_name::*;
771pub use arranger_name::*;
772pub use composer_name::*;
773pub use composition_name::*;
774pub use copyright_notice::*;
775pub use lyricist_name::*;
776pub use lyrics::*;
777pub use lyrics_language::*;
778pub use midi_clip_name::*;
779pub use packet::{Format, Packet};
780pub use primary_performer_name::*;
781pub use project_name::*;
782pub use publisher_name::*;
783pub use recording_date::*;
784pub use recording_location::*;
785pub use ruby::*;
786pub use ruby_language::*;
787pub use set_chord_name::{
788    Alteration, ChordType, SetChordName, SharpsFlats as SetChordNameSharpsFlats,
789};
790pub use set_key_signature::{SetKeySignature, SharpsFlats as SetKeySignatureSharpsFlats};
791pub use set_metronome::*;
792pub use set_tempo::*;
793pub use set_time_signature::*;
794pub use text::TextBytesIterator;
795pub use tonic::Tonic;
796pub use unknown_metadata_text::*;
797pub use unknown_performance_text::*;
798
799pub(crate) const UMP_MESSAGE_TYPE: u8 = 0xD;
800pub(crate) const COMPLETE_FORMAT: u8 = 0x0;
801pub(crate) const START_FORMAT: u8 = 0x1;
802pub(crate) const CONTINUE_FORMAT: u8 = 0x2;
803pub(crate) const END_FORMAT: u8 = 0x3;
804pub(crate) const SETUP_AND_PERFORMANCE_BANK: u8 = 0x0;
805pub(crate) const METADATA_TEXT_BANK: u8 = 0x1;
806pub(crate) const PERFORMANCE_TEXT_BANK: u8 = 0x2;
807
808#[derive(
809    derive_more::From,
810    midi2_proc::Data,
811    midi2_proc::Packets,
812    midi2_proc::Grouped,
813    midi2_proc::RebufferFrom,
814    midi2_proc::TryRebufferFrom,
815    Clone,
816    Copy,
817    Debug,
818    PartialEq,
819    Eq,
820)]
821#[non_exhaustive]
822pub enum FlexData<B: crate::buffer::Ump> {
823    SetChordName(set_chord_name::SetChordName<B>),
824    SetKeySignature(set_key_signature::SetKeySignature<B>),
825    SetMetronome(set_metronome::SetMetronome<B>),
826    SetTempo(set_tempo::SetTempo<B>),
827    SetTimeSignature(set_time_signature::SetTimeSignature<B>),
828    UnknownMetadataText(unknown_metadata_text::UnknownMetadataText<B>),
829    ProjectName(project_name::ProjectName<B>),
830    CompositionName(composition_name::CompositionName<B>),
831    MidiClipName(midi_clip_name::MidiClipName<B>),
832    CopyrightNotice(copyright_notice::CopyrightNotice<B>),
833    ComposerName(composer_name::ComposerName<B>),
834    LyricistName(lyricist_name::LyricistName<B>),
835    ArrangerName(arranger_name::ArrangerName<B>),
836    PublisherName(publisher_name::PublisherName<B>),
837    PrimaryPerformerName(primary_performer_name::PrimaryPerformerName<B>),
838    AccompanyingPerformerName(accompanying_performer_name::AccompanyingPerformerName<B>),
839    RecordingDate(recording_date::RecordingDate<B>),
840    RecordingLocation(recording_location::RecordingLocation<B>),
841    UnknownPerformanceText(unknown_performance_text::UnknownPerformanceText<B>),
842    Lyrics(lyrics::Lyrics<B>),
843    LyricsLanguage(lyrics_language::LyricsLanguage<B>),
844    Ruby(ruby::Ruby<B>),
845    RubyLanguage(ruby_language::RubyLanguage<B>),
846}
847
848impl<'a> TryFrom<&'a [u32]> for FlexData<&'a [u32]> {
849    type Error = crate::error::InvalidData;
850    fn try_from(value: &'a [u32]) -> Result<Self, Self::Error> {
851        use FlexData::*;
852        if value.is_empty() {
853            return Err(crate::error::InvalidData(
854                crate::detail::common_err_strings::ERR_SLICE_TOO_SHORT,
855            ));
856        };
857        Ok(match value[0].word(1) {
858            0x00_00 => SetTempo(set_tempo::SetTempo::try_from(value)?),
859            0x00_01 => SetTimeSignature(set_time_signature::SetTimeSignature::try_from(value)?),
860            0x00_02 => SetMetronome(set_metronome::SetMetronome::try_from(value)?),
861            0x00_05 => SetKeySignature(set_key_signature::SetKeySignature::try_from(value)?),
862            0x00_06 => SetChordName(set_chord_name::SetChordName::try_from(value)?),
863            0x01_00 => {
864                UnknownMetadataText(unknown_metadata_text::UnknownMetadataText::try_from(value)?)
865            }
866            0x01_01 => ProjectName(project_name::ProjectName::try_from(value)?),
867            0x01_02 => CompositionName(composition_name::CompositionName::try_from(value)?),
868            0x01_03 => MidiClipName(midi_clip_name::MidiClipName::try_from(value)?),
869            0x01_04 => CopyrightNotice(copyright_notice::CopyrightNotice::try_from(value)?),
870            0x01_05 => ComposerName(composer_name::ComposerName::try_from(value)?),
871            0x01_06 => LyricistName(lyricist_name::LyricistName::try_from(value)?),
872            0x01_07 => ArrangerName(arranger_name::ArrangerName::try_from(value)?),
873            0x01_08 => PublisherName(publisher_name::PublisherName::try_from(value)?),
874            0x01_09 => PrimaryPerformerName(
875                primary_performer_name::PrimaryPerformerName::try_from(value)?,
876            ),
877            0x01_10 => AccompanyingPerformerName(
878                accompanying_performer_name::AccompanyingPerformerName::try_from(value)?,
879            ),
880            0x01_11 => RecordingDate(recording_date::RecordingDate::try_from(value)?),
881            0x01_12 => RecordingLocation(recording_location::RecordingLocation::try_from(value)?),
882            0x02_00 => UnknownPerformanceText(
883                unknown_performance_text::UnknownPerformanceText::try_from(value)?,
884            ),
885            0x02_01 => Lyrics(lyrics::Lyrics::try_from(value)?),
886            0x02_02 => LyricsLanguage(lyrics_language::LyricsLanguage::try_from(value)?),
887            0x02_03 => Ruby(ruby::Ruby::try_from(value)?),
888            0x02_04 => RubyLanguage(ruby_language::RubyLanguage::try_from(value)?),
889            _ => Err(crate::error::InvalidData(
890                "Couldn't interpret flex data status / bank fields",
891            ))?,
892        })
893    }
894}
895
896impl<B: Ump> FlexDataMessage<B> for FlexData<B> {}
897
898#[derive(Debug, Clone, Copy, PartialEq, Eq)]
899pub enum Bank {
900    SetupAndPerformance,
901    MetadataText,
902    PerformanceText,
903}
904
905pub trait FlexDataMessage<B: crate::buffer::Ump>: crate::traits::Data<B> {
906    fn bank(&self) -> Bank {
907        use Bank::*;
908        match (self.data()[0] & 0x0000_FF00) >> 8 {
909            0x0 => SetupAndPerformance,
910            0x1 => MetadataText,
911            0x2 => PerformanceText,
912            _ => panic!(),
913        }
914    }
915    fn status(&self) -> u8 {
916        self.data()[0].octet(3)
917    }
918}
919
920struct StatusProperty<const STATUS: u8>;
921
922impl<const STATUS: u8, B: Ump> Property<B> for StatusProperty<STATUS> {
923    type Type = ();
924}
925
926impl<'a, const STATUS: u8, B: Ump> ReadProperty<'a, B> for StatusProperty<STATUS> {
927    fn read(_buffer: &'a B) -> Self::Type {}
928    fn validate(buffer: &B) -> Result<(), crate::error::InvalidData> {
929        if buffer
930            .buffer()
931            .chunks_exact(4)
932            .all(|packet| packet[0].octet(3) == STATUS)
933        {
934            Ok(())
935        } else {
936            Err(crate::error::InvalidData("Incorrect message status"))
937        }
938    }
939}
940
941impl<const STATUS: u8, B: Ump + BufferMut> WriteProperty<B> for StatusProperty<STATUS> {
942    fn write(buffer: &mut B, _v: Self::Type) {
943        buffer.buffer_mut()[0].set_octet(3, STATUS);
944    }
945    fn validate(_v: &Self::Type) -> Result<(), crate::error::InvalidData> {
946        Ok(())
947    }
948    fn default() -> Self::Type {}
949}
950
951struct BankProperty<const BANK: u8>;
952
953impl<const BANK: u8, B: Ump> Property<B> for BankProperty<BANK> {
954    type Type = ();
955}
956
957impl<'a, const BANK: u8, B: Ump> ReadProperty<'a, B> for BankProperty<BANK> {
958    fn read(_buffer: &'a B) -> Self::Type {}
959    fn validate(buffer: &B) -> Result<(), crate::error::InvalidData> {
960        if buffer
961            .buffer()
962            .chunks_exact(4)
963            .all(|packet| packet[0].octet(2) == BANK)
964        {
965            Ok(())
966        } else {
967            Err(crate::error::InvalidData("Incorrect message bank"))
968        }
969    }
970}
971
972impl<const BANK: u8, B: Ump + BufferMut> WriteProperty<B> for BankProperty<BANK> {
973    fn write(buffer: &mut B, _v: Self::Type) {
974        buffer.buffer_mut()[0].set_octet(2, BANK);
975    }
976    fn validate(_v: &Self::Type) -> Result<(), crate::error::InvalidData> {
977        Ok(())
978    }
979    fn default() -> Self::Type {}
980}
981
982struct FormatProperty<const FORMAT: u8>;
983
984impl<const FORMAT: u8, B: Ump> Property<B> for FormatProperty<FORMAT> {
985    type Type = ();
986}
987
988impl<'a, const FORMAT: u8, B: Ump> ReadProperty<'a, B> for FormatProperty<FORMAT> {
989    fn read(_buffer: &'a B) -> Self::Type {}
990    fn validate(buffer: &B) -> Result<(), crate::error::InvalidData> {
991        if FORMAT == u8::from(buffer.buffer()[0].crumb(4)) {
992            Ok(())
993        } else {
994            Err(crate::error::InvalidData("Incorrect message format"))
995        }
996    }
997}
998
999impl<const FORMAT: u8, B: Ump + BufferMut> WriteProperty<B> for FormatProperty<FORMAT> {
1000    fn write(buffer: &mut B, _v: Self::Type) {
1001        buffer.buffer_mut()[0].set_crumb(4, crate::ux::u2::new(FORMAT));
1002    }
1003    fn validate(_v: &Self::Type) -> Result<(), crate::error::InvalidData> {
1004        Ok(())
1005    }
1006    fn default() -> Self::Type {}
1007}
1008
1009struct OptionalChannelProperty;
1010
1011impl<B: Ump> Property<B> for OptionalChannelProperty {
1012    type Type = Option<crate::ux::u4>;
1013}
1014
1015impl<'a, B: Ump> ReadProperty<'a, B> for OptionalChannelProperty {
1016    fn read(buffer: &'a B) -> Self::Type {
1017        optional_channel_from_slice(buffer.buffer())
1018    }
1019    fn validate(_buffer: &B) -> Result<(), crate::error::InvalidData> {
1020        Ok(())
1021    }
1022}
1023
1024impl<B: Ump + BufferMut> WriteProperty<B> for OptionalChannelProperty {
1025    fn write(buffer: &mut B, v: Self::Type) {
1026        let buffer_slice = buffer.buffer_mut();
1027        let data = buffer_slice;
1028        optional_channel_to_slice(data, v);
1029    }
1030    fn validate(_v: &Self::Type) -> Result<(), crate::error::InvalidData> {
1031        Ok(())
1032    }
1033    fn default() -> Self::Type {
1034        Default::default()
1035    }
1036}
1037
1038fn optional_channel_to_slice(data: &mut [u32], channel: Option<crate::ux::u4>) {
1039    use crate::ux::{u2, u4};
1040    match channel {
1041        Some(channel) => {
1042            data[0].set_crumb(5, u2::new(0x0));
1043            data[0].set_nibble(3, channel);
1044        }
1045        None => {
1046            data[0].set_crumb(5, u2::new(0x1));
1047            data[0].set_nibble(3, u4::new(0x0));
1048        }
1049    }
1050}
1051
1052fn optional_channel_from_slice(data: &[u32]) -> Option<ux::u4> {
1053    if data[0].crumb(5) == ux::u2::new(0x0) {
1054        Some(data[0].nibble(3))
1055    } else {
1056        None
1057    }
1058}
1059
1060struct NoChannelProperty;
1061
1062impl<B: Ump> Property<B> for NoChannelProperty {
1063    type Type = ();
1064}
1065
1066impl<'a, B: Ump> ReadProperty<'a, B> for NoChannelProperty {
1067    fn read(_buffer: &'a B) -> Self::Type {}
1068    fn validate(buffer: &B) -> Result<(), crate::error::InvalidData> {
1069        use crate::ux::u2;
1070        if buffer.buffer()[0].crumb(5) != u2::new(0x0) {
1071            Ok(())
1072        } else {
1073            Err(crate::error::InvalidData(
1074                "Address field should be non zero.",
1075            ))
1076        }
1077    }
1078}
1079
1080impl<B: Ump + BufferMut> WriteProperty<B> for NoChannelProperty {
1081    fn write(buffer: &mut B, _: Self::Type) {
1082        use crate::ux::u2;
1083        use crate::ux::u4;
1084
1085        let data = buffer.buffer_mut();
1086        data[0].set_crumb(5, u2::new(0x1));
1087        data[0].set_nibble(3, u4::new(0x0));
1088    }
1089    fn validate(_v: &Self::Type) -> Result<(), crate::error::InvalidData> {
1090        Ok(())
1091    }
1092    fn default() -> Self::Type {
1093        Default::default()
1094    }
1095}
1096
1097struct ConsistentFormatsProperty;
1098
1099impl<B: Ump> Property<B> for ConsistentFormatsProperty {
1100    type Type = ();
1101}
1102
1103impl<'a, B: Ump> ReadProperty<'a, B> for ConsistentFormatsProperty {
1104    fn read(_buffer: &'a B) -> Self::Type {}
1105
1106    fn validate(buffer: &B) -> Result<(), crate::error::InvalidData> {
1107        use crate::detail::helpers::validate_sysex_group_statuses;
1108
1109        validate_sysex_group_statuses(
1110            buffer.buffer(),
1111            |p| u8::from(p[0].crumb(4)) == COMPLETE_FORMAT,
1112            |p| u8::from(p[0].crumb(4)) == START_FORMAT,
1113            |p| u8::from(p[0].crumb(4)) == CONTINUE_FORMAT,
1114            |p| u8::from(p[0].crumb(4)) == END_FORMAT,
1115            4,
1116            crate::ux::u4::new(UMP_MESSAGE_TYPE),
1117        )
1118    }
1119}
1120
1121struct GroupProperty;
1122
1123impl<B: Ump> Property<B> for GroupProperty {
1124    type Type = crate::ux::u4;
1125}
1126
1127impl<'a, B: Ump> ReadProperty<'a, B> for GroupProperty {
1128    fn read(buffer: &'a B) -> Self::Type {
1129        buffer.buffer()[0].nibble(1)
1130    }
1131    fn validate(buffer: &B) -> Result<(), crate::error::InvalidData> {
1132        use crate::detail::helpers::sysex_group_consistent_groups;
1133        sysex_group_consistent_groups(buffer.buffer(), 4, crate::ux::u4::new(UMP_MESSAGE_TYPE))
1134    }
1135}
1136
1137impl<B: Ump + BufferMut> WriteProperty<B> for GroupProperty {
1138    fn write(buffer: &mut B, group: Self::Type) {
1139        for packet in buffer
1140            .buffer_mut()
1141            .chunks_exact_mut(4)
1142            .take_while(|packet| u8::from(packet[0].nibble(0)) == UMP_MESSAGE_TYPE)
1143        {
1144            packet[0].set_nibble(1, group);
1145        }
1146    }
1147    fn validate(_v: &Self::Type) -> Result<(), crate::error::InvalidData> {
1148        Ok(())
1149    }
1150    fn default() -> Self::Type {
1151        Default::default()
1152    }
1153}
1154
1155fn flex_data_dyn_size<B: crate::buffer::Ump>(buffer: &B) -> usize {
1156    buffer
1157        .buffer()
1158        .chunks_exact(4)
1159        .position(|p| {
1160            let status: u8 = p[0].crumb(4).into();
1161            status == COMPLETE_FORMAT || status == END_FORMAT
1162        })
1163        .expect("Message is in an invalid state. Couldn't find end packet.")
1164        * 4
1165        + 4
1166}
1167
1168fn bank_from_buffer(buffer: &[u32]) -> u8 {
1169    buffer[0].octet(2)
1170}
1171
1172fn status_from_buffer(buffer: &[u32]) -> u8 {
1173    buffer[0].octet(3)
1174}
1175
1176fn bank_to_buffer(buffer: &mut [u32], bank: u8) {
1177    buffer[0].set_octet(2, bank);
1178}
1179
1180fn status_to_buffer(buffer: &mut [u32], status: u8) {
1181    buffer[0].set_octet(3, status);
1182}
1183
1184fn clear_payload(buffer: &mut [u32]) {
1185    for packet in buffer.chunks_exact_mut(4) {
1186        packet[1] = 0x0;
1187        packet[2] = 0x0;
1188        packet[3] = 0x0;
1189    }
1190}
1191
1192#[cfg(test)]
1193mod tests {
1194    use super::*;
1195
1196    #[test]
1197    fn try_from_empty() {
1198        let buffer = [];
1199        assert_eq!(
1200            FlexData::try_from(&buffer[..]),
1201            Err(crate::error::InvalidData("Slice is too short")),
1202        );
1203    }
1204
1205    #[test]
1206    fn try_from_text() {
1207        let buffer = [
1208            0xD050_0106,
1209            0x4769_6D6D,
1210            0x6520_736F,
1211            0x6D65_2073,
1212            0xD0D0_0106,
1213            0x6967_6E61,
1214            0x6C21_0000,
1215            0x0000_0000,
1216        ];
1217        assert_eq!(
1218            FlexData::try_from(&buffer[..]),
1219            Ok(FlexData::LyricistName(
1220                lyricist_name::LyricistName::try_from(&buffer[..]).unwrap()
1221            ))
1222        );
1223    }
1224
1225    #[test]
1226    fn try_from_set_tempo() {
1227        let buffer = [0xD710_0000_u32, 0xF751_FE05];
1228        assert_eq!(
1229            FlexData::try_from(&buffer[..]),
1230            Ok(FlexData::SetTempo(
1231                set_tempo::SetTempo::try_from(&buffer[..]).unwrap()
1232            ))
1233        );
1234    }
1235
1236    #[test]
1237    fn read_bank() {
1238        assert_eq!(
1239            FlexData::try_from(&[0xD710_0000_u32, 0xF751_FE05][..])
1240                .unwrap()
1241                .bank(),
1242            Bank::SetupAndPerformance,
1243        );
1244    }
1245
1246    #[test]
1247    fn packets() {
1248        use crate::Packets;
1249
1250        let message = FlexData::try_from(
1251            &[
1252                0xD050_0106,
1253                0x4769_6D6D,
1254                0x6520_736F,
1255                0x6D65_2073,
1256                0xD0D0_0106,
1257                0x6967_6E61,
1258                0x6C21_0000,
1259                0x0000_0000,
1260            ][..],
1261        )
1262        .unwrap();
1263        let mut packets = message.packets();
1264
1265        assert_eq!(
1266            &*packets.next().unwrap(),
1267            &[0xD050_0106, 0x4769_6D6D, 0x6520_736F, 0x6D65_2073,][..],
1268        );
1269        assert_eq!(
1270            &*packets.next().unwrap(),
1271            &[0xD0D0_0106, 0x6967_6E61, 0x6C21_0000, 0x0000_0000,][..],
1272        );
1273        assert_eq!(packets.next(), None);
1274    }
1275
1276    #[test]
1277    fn try_from_set_chord_name_data() {
1278        let message = FlexData::try_from(&[0xD70B_0006, 0xF703_3519, 0x4B00_0000, 0x110A_0020][..]);
1279        message.expect("Valid data");
1280    }
1281}