1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
mod assignable_controller;
mod assignable_per_note_controller;
mod attribute;
mod channel_pitch_bend;
mod channel_pressure;
mod control_change;
mod controller;
mod key_pressure;
mod note_off;
mod note_on;
mod per_note_management;
mod per_note_pitch_bend;
mod program_change;
mod registered_controller;
mod registered_per_note_controller;
mod relative_assignable_controller;
mod relative_registered_controller;

pub use assignable_controller::*;
pub use assignable_per_note_controller::*;
pub use attribute::Attribute as NoteAttribute;
pub use channel_pitch_bend::*;
pub use channel_pressure::*;
pub use control_change::*;
pub use controller::Controller;
pub use key_pressure::*;
pub use note_off::*;
pub use note_on::*;
pub use per_note_management::*;
pub use per_note_pitch_bend::*;
pub use program_change::*;
pub use registered_controller::*;
pub use registered_per_note_controller::*;
pub use relative_assignable_controller::*;
pub use relative_registered_controller::*;

pub(crate) const UMP_MESSAGE_TYPE: u8 = 0x4;

#[derive(
    derive_more::From,
    midi2_proc::Data,
    midi2_proc::Packets,
    midi2_proc::Channeled,
    midi2_proc::Grouped,
    midi2_proc::RebufferFrom,
    midi2_proc::RebufferFromArray,
    midi2_proc::TryRebufferFrom,
    Clone,
    Debug,
    PartialEq,
    Eq,
)]
pub enum ChannelVoice2<B: crate::buffer::Ump> {
    AssignableController(assignable_controller::AssignableController<B>),
    AssignablePerNoteController(assignable_per_note_controller::AssignablePerNoteController<B>),
    ChannelPitchBend(channel_pitch_bend::ChannelPitchBend<B>),
    ChannelPressure(channel_pressure::ChannelPressure<B>),
    ControlChange(control_change::ControlChange<B>),
    KeyPressure(key_pressure::KeyPressure<B>),
    NoteOff(note_off::NoteOff<B>),
    NoteOn(note_on::NoteOn<B>),
    PerNoteManagement(per_note_management::PerNoteManagement<B>),
    PerNotePitchBend(per_note_pitch_bend::PerNotePitchBend<B>),
    ProgramChange(program_change::ProgramChange<B>),
    RegisteredController(registered_controller::RegisteredController<B>),
    RegisteredPerNoteController(registered_per_note_controller::RegisteredPerNoteController<B>),
    RelativeAssignableController(relative_assignable_controller::RelativeAssignableController<B>),
    RelativeRegisteredController(relative_registered_controller::RelativeRegisteredController<B>),
}

impl<'a> TryFrom<&'a [u32]> for ChannelVoice2<&'a [u32]> {
    type Error = crate::error::InvalidData;
    fn try_from(buffer: &'a [u32]) -> Result<Self, Self::Error> {
        if buffer.len() < 1 {
            return Err(crate::error::InvalidData("Slice is too short"));
        };

        use crate::detail::BitOps;

        Ok(match u8::from(buffer[0].nibble(2)) {
            assignable_controller::STATUS => {
                assignable_controller::AssignableController::try_from(buffer)?.into()
            }
            assignable_per_note_controller::STATUS => {
                assignable_per_note_controller::AssignablePerNoteController::try_from(buffer)?
                    .into()
            }
            channel_pitch_bend::STATUS => {
                channel_pitch_bend::ChannelPitchBend::try_from(buffer)?.into()
            }
            channel_pressure::STATUS => channel_pressure::ChannelPressure::try_from(buffer)?.into(),
            control_change::STATUS => control_change::ControlChange::try_from(buffer)?.into(),
            key_pressure::STATUS => key_pressure::KeyPressure::try_from(buffer)?.into(),
            note_off::STATUS => note_off::NoteOff::try_from(buffer)?.into(),
            note_on::STATUS => note_on::NoteOn::try_from(buffer)?.into(),
            per_note_management::STATUS => {
                per_note_management::PerNoteManagement::try_from(buffer)?.into()
            }
            per_note_pitch_bend::STATUS => {
                per_note_pitch_bend::PerNotePitchBend::try_from(buffer)?.into()
            }
            program_change::STATUS => program_change::ProgramChange::try_from(buffer)?.into(),
            registered_controller::STATUS => {
                registered_controller::RegisteredController::try_from(buffer)?.into()
            }
            registered_per_note_controller::STATUS => {
                registered_per_note_controller::RegisteredPerNoteController::try_from(buffer)?
                    .into()
            }
            relative_assignable_controller::STATUS => {
                relative_assignable_controller::RelativeAssignableController::try_from(buffer)?
                    .into()
            }
            relative_registered_controller::STATUS => {
                relative_registered_controller::RelativeRegisteredController::try_from(buffer)?
                    .into()
            }
            _ => Err(crate::error::InvalidData(
                "Unknown midi2 channel voice status",
            ))?,
        })
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use pretty_assertions::assert_eq;

    #[test]
    fn channel() {
        use crate::traits::Channeled;
        use crate::ux::u4;

        assert_eq!(
            ChannelVoice2::try_from(&[0x4BAC_5900, 0xC0B83064][..])
                .unwrap()
                .channel(),
            u4::new(0xC),
        );
    }

    #[test]
    fn packets() {
        use crate::Packets;

        let message = ChannelVoice2::try_from(&[0x4BAC_5900, 0xC0B83064][..]).unwrap();
        let mut packets = message.packets();
        assert_eq!(packets.next(), Some(&[0x4BAC_5900, 0xC0B83064][..]));
        assert_eq!(packets.next(), None);
    }

    #[test]
    fn rebuffer_from_array() {
        use crate::RebufferFrom;

        let message = ChannelVoice2::try_from(&[0x4BAC_5900, 0xC0B83064][..]).unwrap();
        let _ = ChannelVoice2::<[u32; 2]>::rebuffer_from(message);
    }
}