ramidier 0.3.0

Akai Pro Apc key 25 abstraction layer
Documentation
use crate::enums::button::knob_ctrl::KnobCtrlKey;
use crate::enums::button::pads::PadKey;
use crate::enums::button::soft_keys::SoftKey;
use crate::errors::mapping::HardwareMappingError;
use crate::io::input_data::MidiInputData;
use midi_msg::{ChannelVoiceMsg, MidiMsg};

pub struct PadsAndKnobsChannel;
pub struct KeyboardChannel;

pub trait ChannelKind {
    type Group;

    fn decode(msg: &MidiMsg) -> Option<MidiInputData<Self::Group>>;
}

impl ChannelKind for PadsAndKnobsChannel {
    type Group = PadsAndKnobsInputGroup;

    fn decode(msg: &MidiMsg) -> Option<MidiInputData<Self::Group>> {
        match msg {
            MidiMsg::ChannelVoice {
                channel,
                msg: ChannelVoiceMsg::NoteOn { note, velocity: _ },
            } => PadsAndKnobsInputGroup::try_from(*note)
                .map(|input_group| MidiInputData {
                    channel: *channel,
                    input_group,
                    value: 1u8,
                })
                .ok(),
            MidiMsg::ChannelVoice {
                channel,
                msg: ChannelVoiceMsg::NoteOff { note, velocity: _ },
            } => PadsAndKnobsInputGroup::try_from(*note)
                .map(|input_group| MidiInputData {
                    channel: *channel,
                    input_group,
                    value: 0u8,
                })
                .ok(),
            MidiMsg::ChannelVoice {
                channel,
                msg: ChannelVoiceMsg::ControlChange { control },
            } => PadsAndKnobsInputGroup::try_from(control.control())
                .map(|input_group| MidiInputData {
                    channel: *channel,
                    input_group,
                    value: control.value(),
                })
                .ok(),
            _ => None,
        }
    }
}

impl ChannelKind for KeyboardChannel {
    type Group = KeyboardInputGroup;

    fn decode(msg: &MidiMsg) -> Option<MidiInputData<Self::Group>> {
        match msg {
            MidiMsg::ChannelVoice {
                channel,
                msg: ChannelVoiceMsg::NoteOn { note, velocity: _ },
            } => KeyboardInputGroup::try_from(*note)
                .map(|input_group| MidiInputData {
                    channel: *channel,
                    input_group,
                    value: 1u8,
                })
                .ok(),
            MidiMsg::ChannelVoice {
                channel,
                msg: ChannelVoiceMsg::NoteOff { note, velocity: _ },
            } => KeyboardInputGroup::try_from(*note)
                .map(|input_group| MidiInputData {
                    channel: *channel,
                    input_group,
                    value: 0u8,
                })
                .ok(),
            _ => None,
        }
    }
}

#[derive(Debug, Copy, Clone)]
pub enum PadsAndKnobsInputGroup {
    Pads(PadKey),
    SoftKeys(SoftKey),
    KnobCtrl(KnobCtrlKey),
    Knob(u8),
    Up,
    Down,
    Right,
    Left,
    StopAllClips,
    Shift,
    ResumePause,
    Start,
}

impl From<PadsAndKnobsInputGroup> for u8 {
    fn from(value: PadsAndKnobsInputGroup) -> Self {
        match value {
            PadsAndKnobsInputGroup::Pads(x) => x.into(),
            PadsAndKnobsInputGroup::SoftKeys(x) => x.into(),
            PadsAndKnobsInputGroup::KnobCtrl(x) => x.into(),
            PadsAndKnobsInputGroup::Up => 64,
            PadsAndKnobsInputGroup::Down => 65,
            PadsAndKnobsInputGroup::Right => 67,
            PadsAndKnobsInputGroup::Left => 66,
            PadsAndKnobsInputGroup::StopAllClips => 81,
            PadsAndKnobsInputGroup::Shift => 98,
            PadsAndKnobsInputGroup::ResumePause => 91,
            PadsAndKnobsInputGroup::Start => 92,
            PadsAndKnobsInputGroup::Knob(index) => index + 47,
        }
    }
}

impl TryFrom<u8> for PadsAndKnobsInputGroup {
    type Error = HardwareMappingError;
    fn try_from(value: u8) -> Result<Self, Self::Error> {
        match value {
            64 => Ok(Self::Up),
            65 => Ok(Self::Down),
            66 => Ok(Self::Left),
            67 => Ok(Self::Right),
            81 => Ok(Self::StopAllClips),
            98 => Ok(Self::Shift),
            91 => Ok(Self::ResumePause),
            93 => Ok(Self::Start),
            0..=39 => PadKey::try_from(value)
                .map_or(Err(Self::Error::InvalidPadIndex(value)), |k| {
                    Ok(Self::Pads(k))
                }),
            48..=55 => Ok(Self::Knob(value - 47)),
            _ => SoftKey::try_from(value).map_or_else(
                |_| {
                    KnobCtrlKey::try_from(value)
                        .map_or(Err(Self::Error::InvalidKnobCtrlIndex(value)), |k| {
                            Ok(Self::KnobCtrl(k))
                        })
                },
                |k| Ok(Self::SoftKeys(k)),
            ),
        }
    }
}

#[derive(Debug, Copy, Clone)]
pub enum KeyboardInputGroup {
    Key(u8),
}

impl From<KeyboardInputGroup> for u8 {
    fn from(value: KeyboardInputGroup) -> Self {
        match value {
            KeyboardInputGroup::Key(x) => x,
        }
    }
}

impl TryFrom<u8> for KeyboardInputGroup {
    type Error = HardwareMappingError;
    fn try_from(value: u8) -> Result<Self, Self::Error> {
        match value {
            48..=72 => Ok(Self::Key(value - 47)),
            _ => Err(Self::Error::InvalidKeyboardKeyIndex(value)),
        }
    }
}