use std::convert::TryFrom;
use std::fmt;
use num_enum::TryFromPrimitive;
use bit::BitIndex;
use strum_macros;
use crate::{
Ranged,
SystemExclusiveData,
ParseError,
MIDIChannel
};
#[derive(Debug, Eq, PartialEq, Copy, Clone, TryFromPrimitive)]
#[repr(u8)]
pub enum Function {
OneBlockDumpRequest = 0x00,
AllBlockDumpRequest = 0x01,
ParameterSend = 0x10,
TrackControl = 0x11,
OneBlockDump = 0x20,
AllBlockDump = 0x21,
ModeChange = 0x31,
Remote = 0x32,
WriteComplete = 0x40,
WriteError = 0x41,
WriteErrorByProtect = 0x42,
WriteErrorByMemoryFull = 0x44,
WriteErrorByNoExpandedMemory = 0x45,
}
pub struct Message {
pub channel: MIDIChannel,
pub function: Function,
pub function_data: Vec<u8>,
pub subdata: Vec<u8>,
pub patch_data: Vec<u8>,
}
impl SystemExclusiveData for Message {
fn from_bytes(data: &[u8]) -> Result<Self, ParseError> {
Ok(Message {
channel: MIDIChannel::new(data[2].into()),
function: Function::try_from(data[3]).unwrap(),
function_data: Vec::<u8>::new(), subdata: Vec::<u8>::new(), patch_data: data[3..].to_vec(),
})
}
fn to_bytes(&self) -> Vec<u8> {
let mut result: Vec<u8> = Vec::new();
result.push(0x40); result.push(self.channel.value() as u8);
result.push(self.function as u8);
result.extend(&self.function_data);
result.extend(&self.subdata);
result.extend(&self.patch_data);
result
}
fn data_size() -> usize {
todo!("Compute K5000 message size")
}
}
#[derive(Debug, PartialEq, Copy, Clone, strum_macros::Display)]
#[repr(u8)]
pub enum Cardinality {
One = 0x20,
Block = 0x21,
}
impl From<Cardinality> for u8 {
fn from(c: Cardinality) -> Self {
c as u8
}
}
#[derive(
Debug,
Eq, PartialEq,
Clone, Copy,
strum_macros::Display, strum_macros::EnumString
)]
#[repr(u8)]
pub enum BankIdentifier {
A = 0x00,
B = 0x01,
D = 0x02, E = 0x03,
F = 0x04,
}
impl From<BankIdentifier> for u8 {
fn from(b: BankIdentifier) -> Self {
b as u8
}
}
impl TryFrom<u8> for BankIdentifier {
type Error = ();
fn try_from(b: u8) -> Result<Self, Self::Error> {
match b {
x if x == BankIdentifier::A as u8 => Ok(BankIdentifier::A),
x if x == BankIdentifier::B as u8 => Ok(BankIdentifier::B),
x if x == BankIdentifier::D as u8 => Ok(BankIdentifier::D),
x if x == BankIdentifier::E as u8 => Ok(BankIdentifier::E),
x if x == BankIdentifier::F as u8 => Ok(BankIdentifier::F),
_ => Err(()),
}
}
}
#[derive(Debug, PartialEq, Copy, Clone)]
#[repr(u8)]
pub enum PatchKind {
Single = 0x00,
Multi = 0x20, DrumKit = 0x10,
DrumInstrument = 0x11,
}
impl From<PatchKind> for u8 {
fn from(val: PatchKind) -> Self {
val as u8
}
}
impl fmt::Display for PatchKind {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", match *self {
PatchKind::Single => "Single",
PatchKind::Multi => "Multi/Combi",
PatchKind::DrumKit => "Drum Kit",
PatchKind::DrumInstrument => "Drum Instrument"
})
}
}
#[derive(Debug, PartialEq)]
pub struct Header {
pub channel: MIDIChannel,
pub cardinality: Cardinality,
pub bank_identifier: Option<BankIdentifier>,
pub kind: PatchKind,
pub sub_bytes: Vec<u8>,
}
impl Header {
pub fn identify_vec(buf: &[u8]) -> Option<Header> {
let channel = MIDIChannel::new((buf[0] + 1).into()); let result = match &buf[1..] {
[0x20, 0x00, 0x0A, 0x00, 0x00, sub1, ..] => {
Some(Header {
channel,
cardinality: Cardinality::One,
bank_identifier: Some(BankIdentifier::A),
kind: PatchKind::Single,
sub_bytes: vec![*sub1]
})
},
[0x20, 0x00, 0x0A, 0x00, 0x01, sub1, ..] => {
Some(Header {
channel,
cardinality: Cardinality::One,
bank_identifier: Some(BankIdentifier::B),
kind: PatchKind::Single,
sub_bytes: vec![*sub1]
})
},
[0x20, 0x00, 0x0A, 0x00, 0x02, sub1, ..] => {
Some(Header {
channel,
cardinality: Cardinality::One,
bank_identifier: Some(BankIdentifier::D),
kind: PatchKind::Single,
sub_bytes: vec![*sub1]
})
},
[0x20, 0x00, 0x0A, 0x00, 0x03, sub1, ..] => {
Some(Header {
channel,
cardinality: Cardinality::One,
bank_identifier: Some(BankIdentifier::E),
kind: PatchKind::Single,
sub_bytes: vec![*sub1],
})
},
[0x20, 0x00, 0x0A, 0x00, 0x04, sub1, ..] => {
Some(Header {
channel,
cardinality: Cardinality::One,
bank_identifier: Some(BankIdentifier::F),
kind: PatchKind::Single,
sub_bytes: vec![*sub1],
})
},
[0x20, 0x00, 0x0A, 0x20, sub1, ..] => {
Some(Header {
channel,
cardinality: Cardinality::One,
bank_identifier: None,
kind: PatchKind::Multi,
sub_bytes: vec![*sub1],
})
},
[0x21, 0x00, 0x0A, 0x00, 0x00, tone_map @ ..] => {
Some(Header {
channel,
cardinality: Cardinality::Block,
bank_identifier: Some(BankIdentifier::A),
kind: PatchKind::Single,
sub_bytes: Vec::from(tone_map),
})
},
[0x21, 0x00, 0x0A, 0x00, 0x01, ..] => {
Some(Header {
channel,
cardinality: Cardinality::Block,
bank_identifier: Some(BankIdentifier::B),
kind: PatchKind::Single,
sub_bytes: vec![],
})
},
[0x21, 0x00, 0x0A, 0x00, 0x02, tone_map @ ..] => {
Some(Header {
channel,
cardinality: Cardinality::Block,
bank_identifier: Some(BankIdentifier::D),
kind: PatchKind::Single,
sub_bytes: Vec::from(tone_map),
})
},
[0x21, 0x00, 0x0A, 0x00, 0x03, tone_map @ ..] => {
Some(Header {
channel,
cardinality: Cardinality::Block,
bank_identifier: Some(BankIdentifier::E),
kind: PatchKind::Single,
sub_bytes: Vec::from(tone_map),
})
},
[0x21, 0x00, 0x0A, 0x00, 0x04, tone_map @ ..] => {
Some(Header {
channel,
cardinality: Cardinality::Block,
bank_identifier: Some(BankIdentifier::F),
kind: PatchKind::Single,
sub_bytes: Vec::from(tone_map),
})
},
[0x21, 0x00, 0x0A, 0x20, ..] => {
Some(Header {
channel,
cardinality: Cardinality::Block,
bank_identifier: None,
kind: PatchKind::Multi,
sub_bytes: vec![],
})
},
[0x20, 0x00, 0x0A, 0x10, ..] => {
Some(Header {
channel,
cardinality: Cardinality::One,
bank_identifier: None,
kind: PatchKind::DrumKit,
sub_bytes: vec![],
})
},
[0x20, 0x00, 0x0A, 0x11, sub1, ..] => {
Some(Header {
channel,
cardinality: Cardinality::One,
bank_identifier: None,
kind: PatchKind::DrumInstrument,
sub_bytes: vec![*sub1],
})
},
[0x21, 0x00, 0x0A, 0x11, ..] => {
Some(Header {
channel,
cardinality: Cardinality::Block,
bank_identifier: None,
kind: PatchKind::DrumInstrument,
sub_bytes: vec![],
})
},
_ => { None }
};
match result {
Some(mut header) => {
if header.sub_bytes.len() > 1 {
header.sub_bytes.truncate(19);
}
Some(header)
},
None => None,
}
}
pub fn size(&self) -> usize {
let mut count =
1 + 1 + 1 + 1 + 1;
if self.kind == PatchKind::Single {
count += 1; }
count += self.sub_bytes.len(); count
}
}
impl fmt::Display for Header {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} {} {}, sub-bytes={:02X?}",
self.cardinality,
self.kind,
if let Some(bank) = &self.bank_identifier {
bank.to_string()
} else {
String::from("N/A")
},
self.sub_bytes
)
}
}
impl SystemExclusiveData for Header {
fn from_bytes(data: &[u8]) -> Result<Self, ParseError> {
if let Some(header) = Header::identify_vec(&data) {
Ok(header)
}
else {
Err(ParseError::InvalidData(0, "unidentified header".to_string()))
}
}
fn to_bytes(&self) -> Vec<u8> {
let mut result = vec![
self.channel.value() as u8,
self.cardinality.into(),
0x00,
0x0A,
self.kind.into(),
];
if self.kind == PatchKind::Single {
result.push(self.bank_identifier.unwrap().into());
}
result.extend(&self.sub_bytes);
result
}
fn data_size() -> usize {
unimplemented!() }
}
pub const MAX_TONE_COUNT: u8 = 128;
pub struct ToneMap {
included: [bool; MAX_TONE_COUNT as usize],
}
impl ToneMap {
pub fn new() -> Self {
ToneMap { included: [false; MAX_TONE_COUNT as usize] }
}
pub fn is_included(&self, tone_number: u8) -> bool {
self.included[tone_number as usize]
}
pub fn included_count(&self) -> usize {
self.included.into_iter().filter(|b| *b).count()
}
}
impl fmt::Display for ToneMap {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut output = String::from("");
for i in 0..MAX_TONE_COUNT {
if self.included[i as usize] {
output.push_str(&format!("{} ", i + 1));
}
}
write!(f, "{}", output)
}
}
impl SystemExclusiveData for ToneMap {
fn from_bytes(data: &[u8]) -> Result<Self, ParseError> {
let mut included = [false; MAX_TONE_COUNT as usize];
let mut i = 0;
let mut tone_number = 0;
while tone_number < MAX_TONE_COUNT {
for n in 0..7 {
included[tone_number as usize] = data[i].bit(n);
tone_number += 1;
if tone_number == MAX_TONE_COUNT {
break;
}
}
i += 1;
}
Ok(ToneMap { included })
}
fn to_bytes(&self) -> Vec<u8> {
let mut result = Vec::<u8>::new();
let chunks = self.included.chunks(7);
for chunk in chunks {
let mut byte = 0u8; for (n, bit) in chunk.iter().enumerate() {
byte.set_bit(n, *bit);
}
result.push(byte);
}
assert_eq!(result.len(), ToneMap::data_size());
result
}
fn data_size() -> usize { 19 }
}
#[cfg(test)]
mod tests {
use super::{*};
#[test]
fn test_one_add_bank_a() {
let cmd: Vec<u8> = vec![ 0x00, 0x20, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00 ]; assert_eq!(
Header::identify_vec(&cmd).unwrap(),
Header {
channel: MIDIChannel::new(1),
cardinality: Cardinality::One,
bank_identifier: Some(BankIdentifier::A),
kind: PatchKind::Single,
sub_bytes: vec![0x00]
}
);
}
#[test]
fn test_one_add_bank_d() {
let cmd: Vec<u8> = vec![ 0x00, 0x20, 0x00, 0x0A, 0x00, 0x02, 0x00 ]; assert_eq!(
Header::identify_vec(&cmd).unwrap(),
Header {
channel: MIDIChannel::new(1),
cardinality: Cardinality::One,
bank_identifier: Some(BankIdentifier::D),
kind: PatchKind::Single,
sub_bytes: vec![0x00]
}
);
}
#[test]
fn test_one_exp_bank_e() {
let cmd: Vec<u8> = vec![ 0x00, 0x20, 0x00, 0x0A, 0x00, 0x03, 0x00 ]; assert_eq!(
Header::identify_vec(&cmd).unwrap(),
Header {
channel: MIDIChannel::new(1),
cardinality: Cardinality::One,
bank_identifier: Some(BankIdentifier::E),
kind: PatchKind::Single,
sub_bytes: vec![0x00]
}
);
}
#[test]
fn test_one_exp_bank_f() {
let cmd: Vec<u8> = vec![ 0x00, 0x20, 0x00, 0x0A, 0x00, 0x04, 0x00 ]; assert_eq!(
Header::identify_vec(&cmd).unwrap(),
Header {
channel: MIDIChannel::new(1),
cardinality: Cardinality::One,
bank_identifier: Some(BankIdentifier::F),
kind: PatchKind::Single,
sub_bytes: vec![0x00]
}
);
}
#[test]
fn test_one_multi() {
let cmd: Vec<u8> = vec![ 0x00, 0x20, 0x00, 0x0A, 0x20, 0x00 ]; assert_eq!(
Header::identify_vec(&cmd).unwrap(),
Header {
channel: MIDIChannel::new(1),
cardinality: Cardinality::One,
bank_identifier: None,
kind: PatchKind::Multi,
sub_bytes: vec![0x00]
}
);
}
#[test]
fn test_block_add_bank_a() {
let cmd: Vec<u8> = vec![ 0x00, 0x21, 0x00, 0x0A, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ];
assert_eq!(
Header::identify_vec(&cmd).unwrap(),
Header {
channel: MIDIChannel::new(1),
cardinality: Cardinality::Block,
bank_identifier: Some(BankIdentifier::A),
kind: PatchKind::Single,
sub_bytes: vec![0x00; 19]
}
);
}
#[test]
fn test_block_add_bank_d() {
let cmd: Vec<u8> = vec![ 0x00, 0x21, 0x00, 0x0A, 0x00, 0x02,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; assert_eq!(
Header::identify_vec(&cmd).unwrap(),
Header {
channel: MIDIChannel::new(1),
cardinality: Cardinality::Block,
bank_identifier: Some(BankIdentifier::D),
kind: PatchKind::Single,
sub_bytes: vec![0x00; 19]
}
);
}
#[test]
fn test_block_exp_bank_e() {
let cmd: Vec<u8> = vec![ 0x00, 0x21, 0x00, 0x0A, 0x00, 0x03,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]; assert_eq!(
Header::identify_vec(&cmd).unwrap(),
Header {
channel: MIDIChannel::new(1),
cardinality: Cardinality::Block,
bank_identifier: Some(BankIdentifier::E),
kind: PatchKind::Single,
sub_bytes: vec![0x00; 19]
}
);
}
#[test]
fn test_block_exp_bank_f() {
let cmd: Vec<u8> = vec![ 0x00, 0x21, 0x00, 0x0A, 0x00, 0x04,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]; assert_eq!(
Header::identify_vec(&cmd).unwrap(),
Header {
channel: MIDIChannel::new(1),
cardinality: Cardinality::Block,
bank_identifier: Some(BankIdentifier::F),
kind: PatchKind::Single,
sub_bytes: vec![0x00; 19]
}
);
}
#[test]
fn test_block_multi() {
let cmd: Vec<u8> = vec![ 0x00, 0x21, 0x00, 0x0A, 0x20 ]; assert_eq!(
Header::identify_vec(&cmd).unwrap(),
Header {
channel: MIDIChannel::new(1),
cardinality: Cardinality::Block,
bank_identifier: None,
kind: PatchKind::Multi,
sub_bytes: vec![]
}
);
}
#[test]
fn test_one_pcm_bank_b() {
let cmd: Vec<u8> = vec![ 0x00, 0x20, 0x00, 0x0A, 0x00, 0x01, 0x00 ]; assert_eq!(
Header::identify_vec(&cmd).unwrap(),
Header {
channel: MIDIChannel::new(1),
cardinality: Cardinality::One,
bank_identifier: Some(BankIdentifier::B),
kind: PatchKind::Single,
sub_bytes: vec![0x00]
}
);
}
#[test]
fn test_block_pcm_bank_b() {
let cmd: Vec<u8> = vec![ 0x00, 0x21, 0x00, 0x0A, 0x00, 0x01 ]; assert_eq!(
Header::identify_vec(&cmd).unwrap(),
Header {
channel: MIDIChannel::new(1),
cardinality: Cardinality::Block,
bank_identifier: Some(BankIdentifier::B),
kind: PatchKind::Single,
sub_bytes: vec![]
}
);
}
#[test]
fn test_one_drum_kit() {
let cmd: Vec<u8> = vec![ 0x00, 0x20, 0x00, 0x0A, 0x10 ]; assert_eq!(
Header::identify_vec(&cmd).unwrap(),
Header {
channel: MIDIChannel::new(1),
cardinality: Cardinality::One,
bank_identifier: None,
kind: PatchKind::DrumKit,
sub_bytes: vec![]
}
);
}
#[test]
fn test_one_drum_instrument() {
let cmd: Vec<u8> = vec![ 0x00, 0x20, 0x00, 0x0A, 0x11, 0x00 ]; assert_eq!(
Header::identify_vec(&cmd).unwrap(),
Header {
channel: MIDIChannel::new(1),
cardinality: Cardinality::One,
bank_identifier: None,
kind: PatchKind::DrumInstrument,
sub_bytes: vec![0x00]
}
);
}
#[test]
fn test_block_drum_instrument() {
let cmd: Vec<u8> = vec![ 0x00, 0x21, 0x00, 0x0A, 0x11 ]; assert_eq!(
Header::identify_vec(&cmd).unwrap(),
Header {
channel: MIDIChannel::new(1),
cardinality: Cardinality::Block,
bank_identifier: None,
kind: PatchKind::DrumInstrument,
sub_bytes: vec![]
}
);
}
}