use crate::parse_error::*;
use crate::util::*;
use ascii::AsciiString;
#[derive(Debug, Clone, PartialEq)]
pub enum SampleDumpMsg {
Request {
sample_num: u16,
},
Header {
sample_num: u16,
format: u8,
period: u32,
length: u32,
sustain_loop_start: u32,
sustain_loop_end: u32,
loop_type: LoopType,
},
Packet {
running_count: u8,
data: Vec<u8>,
},
LoopPointsRequest {
sample_num: u16,
loop_num: LoopNumber,
},
LoopPointTransmission {
sample_num: u16,
loop_num: LoopNumber,
loop_type: LoopType,
start_addr: u32,
end_addr: u32,
},
}
impl SampleDumpMsg {
pub(crate) fn extend_midi(&self, v: &mut Vec<u8>) {
match self {
Self::Header {
sample_num,
format,
period,
length,
sustain_loop_start,
sustain_loop_end,
loop_type,
} => {
push_u14(*sample_num, v);
v.push((*format).min(28).max(8));
push_u21(*period, v);
push_u21(*length, v);
push_u21(*sustain_loop_start, v);
push_u21(*sustain_loop_end, v);
v.push(*loop_type as u8);
}
Self::Packet {
running_count,
data,
} => {
let mut p: [u8; 120] = [0; 120];
for (i, b) in data.iter().enumerate() {
if i > 119 {
break;
}
p[i] = to_u7(*b);
}
v.push(to_u7(*running_count));
v.extend_from_slice(&p);
v.push(0);
}
Self::Request { sample_num } => {
push_u14(*sample_num, v);
}
Self::LoopPointTransmission {
sample_num,
loop_num,
loop_type,
start_addr,
end_addr,
} => {
push_u14(*sample_num, v);
loop_num.extend_midi(v);
v.push(*loop_type as u8);
push_u21(*start_addr, v);
push_u21(*end_addr, v);
}
Self::LoopPointsRequest {
sample_num,
loop_num,
} => {
push_u14(*sample_num, v);
loop_num.extend_midi(v);
}
}
}
#[allow(dead_code)]
pub(crate) fn from_midi(_m: &[u8]) -> Result<(Self, usize), ParseError> {
Err(ParseError::Invalid(format!("TODO: Not implemented")))
}
pub fn packet(num: u32, mut data: [u8; 120]) -> Self {
for d in data.iter_mut() {
*d = to_u7(*d);
}
Self::Packet {
running_count: (num % 128) as u8,
data: data.to_vec(),
}
}
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum LoopNumber {
Loop(u16),
RequestAll,
DeleteAll,
}
impl LoopNumber {
fn extend_midi(&self, v: &mut Vec<u8>) {
match self {
Self::RequestAll => {
v.push(0x7F);
v.push(0x7F);
}
Self::DeleteAll => {
v.push(0x7F);
v.push(0x7F);
}
Self::Loop(x) => push_u14(*x, v),
}
}
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum LoopType {
Forward = 0,
BiDirectional = 1,
Off = 127,
}
#[derive(Debug, Clone, PartialEq)]
pub enum ExtendedSampleDumpMsg {
Header {
sample_num: u16,
format: u8,
sample_rate: f64,
length: u64,
sustain_loop_start: u64,
sustain_loop_end: u64,
loop_type: ExtendedLoopType,
num_channels: u8,
},
SampleNameRequest {
sample_num: u16,
},
SampleName {
sample_num: u16,
name: AsciiString,
},
LoopPointsRequest {
sample_num: u16,
loop_num: LoopNumber,
},
LoopPointTransmission {
sample_num: u16,
loop_num: LoopNumber,
loop_type: ExtendedLoopType,
start_addr: u64,
end_addr: u64,
},
}
impl ExtendedSampleDumpMsg {
pub(crate) fn extend_midi(&self, v: &mut Vec<u8>) {
match self {
Self::Header {
sample_num,
format,
sample_rate,
length,
sustain_loop_start,
sustain_loop_end,
loop_type,
num_channels,
} => {
push_u14(*sample_num, v);
v.push((*format).min(28).max(8));
let sample_rate = sample_rate.max(0.0);
let sample_rate_integer = sample_rate.floor();
push_u28(sample_rate_integer as u32, v);
push_u28(
((sample_rate - sample_rate_integer) * 2.0f64.powi(28)) as u32,
v,
);
push_u35((*length).min(34359738368), v);
push_u35((*sustain_loop_start).min(34359738367), v);
push_u35((*sustain_loop_end).min(34359738367), v);
v.push(*loop_type as u8);
push_u7(*num_channels, v);
}
Self::LoopPointTransmission {
sample_num,
loop_num,
loop_type,
start_addr,
end_addr,
} => {
push_u14(*sample_num, v);
loop_num.extend_midi(v);
v.push(*loop_type as u8);
push_u35(*start_addr, v);
push_u35(*end_addr, v);
}
Self::LoopPointsRequest {
sample_num,
loop_num,
} => {
push_u14(*sample_num, v);
loop_num.extend_midi(v);
}
Self::SampleName { sample_num, name } => {
push_u14(*sample_num, v);
v.push(0);
let len = name.len().min(127);
v.push(len as u8);
v.extend_from_slice(&name.as_bytes()[0..len]);
}
Self::SampleNameRequest { sample_num } => {
push_u14(*sample_num, v);
}
}
}
#[allow(dead_code)]
pub(crate) fn from_midi(_m: &[u8]) -> Result<(Self, usize), ParseError> {
Err(ParseError::Invalid(format!("TODO: Not implemented")))
}
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum ExtendedLoopType {
Forward = 0x00,
BiDirectional = 0x01,
ForwardRelease = 0x02,
BiDirectionalRelease = 0x03,
Backward = 0x40,
BackwardBiDirectional = 0x41,
BackwardRelease = 0x42,
BackwardBiDirectionalRelease = 0x43,
BackwardOneShot = 0x7E,
OneShot = 0x7F,
}
#[cfg(test)]
mod tests {
use crate::*;
#[test]
fn serialize_sample_dump_msg() {
assert_eq!(
MidiMsg::SystemExclusive {
msg: SystemExclusiveMsg::UniversalNonRealTime {
device: DeviceID::AllCall,
msg: UniversalNonRealTimeMsg::ExtendedSampleDump(
ExtendedSampleDumpMsg::Header {
sample_num: 5,
format: 8,
sample_rate: 4000.5,
length: 2u64.pow(30),
sustain_loop_start: 2u64.pow(10),
sustain_loop_end: 2u64.pow(20),
loop_type: ExtendedLoopType::BiDirectionalRelease,
num_channels: 2
}
),
},
}
.to_midi(),
vec![
0xF0, 0x7E, 0x7F,
0x05, 0x05,
05, 00,
8,
0b0100000, 0b0011111, 0, 0,
0, 0, 0, 0x40,
0, 0, 0, 0, 0b0000100,
0, 0b0001000, 0, 0, 0,
0, 0, 0b1000000, 0, 0,
0x03,
2,
0xF7
]
);
}
}