use std::convert::TryFrom;
use std::fmt;
use log::debug;
use bit::BitIndex;
use crate::{
SystemExclusiveData,
ParseError,
Checksum,
MIDIChannel,
Ranged
};
use crate::k4::{
DRUM_NOTE_COUNT,
Level,
ModulationDepth,
Decay
};
use crate::k4::wave::Wave;
use crate::k4::effect::Submix;
pub struct DrumPatch {
pub common: Common,
pub notes: [Note; DRUM_NOTE_COUNT],
}
impl Default for DrumPatch {
fn default() -> Self {
DrumPatch {
common: Default::default(),
notes: [Default::default(); DRUM_NOTE_COUNT],
}
}
}
impl DrumPatch {
fn collect_data(&self) -> Vec<u8> {
let mut buf: Vec<u8> = Vec::new();
buf.extend(self.common.to_bytes());
for i in 0..DRUM_NOTE_COUNT {
buf.extend(self.notes[i].to_bytes()); }
buf
}
}
impl fmt::Display for DrumPatch {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut notes_str = String::new();
for i in 0..DRUM_NOTE_COUNT {
notes_str.push_str(&format!("{}: {}\n", i, self.notes[i]));
}
write!(
f,
"COMMON: {}\nNOTES:\n{}",
self.common, notes_str
)
}
}
impl SystemExclusiveData for DrumPatch {
fn from_bytes(data: &[u8]) -> Result<Self, ParseError> {
let common = Common::from_bytes(&data[0..]);
let mut offset = Common::data_size();
let mut notes = [Default::default(); DRUM_NOTE_COUNT];
for i in 0..DRUM_NOTE_COUNT {
debug!("Parsing drum note {}, offset = {}", i, offset);
let note = Note::from_bytes(&data[offset..])?;
notes[i] = note;
offset += Note::data_size();
}
Ok(DrumPatch {
common: common?,
notes,
})
}
fn to_bytes(&self) -> Vec<u8> {
let mut buf: Vec<u8> = Vec::new();
let data = self.collect_data();
buf.extend(data);
buf
}
fn data_size() -> usize {
Common::data_size()
+ Note::data_size() * DRUM_NOTE_COUNT
}
}
pub struct Common {
pub channel: MIDIChannel, pub volume: Level, pub velocity_depth: ModulationDepth, }
impl Default for Common {
fn default() -> Self {
Common {
channel: MIDIChannel::new(10),
volume: Level::new(100),
velocity_depth: ModulationDepth::new(0),
}
}
}
impl Common {
pub fn new() -> Self {
Default::default()
}
}
impl fmt::Display for Common {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"channel = {}, volume = {}, vel.depth = {}",
self.channel.value(),
self.volume.value(),
self.velocity_depth.value()
)
}
}
impl Common {
fn collect_data(&self) -> Vec<u8> {
vec![
self.channel.value() as u8 - 1,
self.volume.value() as u8,
(self.velocity_depth.value() + 50) as u8,
0, 0, 0, 0, 0, 0, 0, ]
}
}
impl Checksum for Common {
fn checksum(&self) -> u8 {
let data = self.collect_data();
let mut total = data.iter().fold(0, |acc, x| acc + ((*x as u32) & 0xFF));
total += 0xA5;
(total & 0x7F) as u8
}
}
impl SystemExclusiveData for Common {
fn from_bytes(data: &[u8]) -> Result<Self, ParseError> {
Ok(Common {
channel: MIDIChannel::new((data[0] + 1) as i32),
volume: Level::new(data[1] as i32),
velocity_depth: ModulationDepth::new((data[2] as i32) - 50),
})
}
fn to_bytes(&self) -> Vec<u8> {
let mut buf: Vec<u8> = Vec::new();
let data = self.collect_data();
buf.extend(data);
buf.push(self.checksum());
buf
}
fn data_size() -> usize {
3 + 7 + 1 }
}
#[derive(Copy, Clone)]
pub struct Note {
pub submix: Submix,
pub source1: Source,
pub source2: Source,
}
impl Default for Note {
fn default() -> Self {
Note {
submix: Submix::A,
source1: Default::default(),
source2: Default::default(),
}
}
}
impl Note {
fn collect_data(&self) -> Vec<u8> {
let mut buf: Vec<u8> = Vec::new();
let mut source1_bytes = self.source1.to_bytes();
let source2_bytes = self.source2.to_bytes();
source1_bytes[0].set_bit_range(4..7, self.submix as u8);
for i in 0..source1_bytes.len() {
buf.push(source1_bytes[i]);
buf.push(source2_bytes[i]);
}
buf
}
}
impl fmt::Display for Note {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"submix = {}, source 1 = {}, source 2 = {}",
self.submix, self.source1, self.source2
)
}
}
impl Checksum for Note {
fn checksum(&self) -> u8 {
let data = self.collect_data();
let mut total = data.iter().fold(0, |acc, x| acc + ((*x as u32) & 0xFF));
total += 0xA5;
(total & 0x7F) as u8
}
}
impl SystemExclusiveData for Note {
fn from_bytes(data: &[u8]) -> Result<Self, ParseError> {
let mut source1_bytes = Vec::<u8>::new();
let mut source2_bytes = Vec::<u8>::new();
let mut i = 0;
while i < 10 {
source1_bytes.push(data[i]);
i += 1;
source2_bytes.push(data[i]);
i += 1;
}
let submix = Submix::try_from(source1_bytes[0] >> 4).unwrap();
source1_bytes[0] &= 0b00001111;
Ok(Note {
submix,
source1: Source::from_bytes(&source1_bytes)?,
source2: Source::from_bytes(&source2_bytes)?,
})
}
fn to_bytes(&self) -> Vec<u8> {
let mut buf: Vec<u8> = Vec::new();
let data = self.collect_data();
buf.extend(data);
buf.push(self.checksum());
buf
}
fn data_size() -> usize {
1 + 2 * Source::data_size()
}
}
#[derive(Copy, Clone)]
pub struct Source {
pub wave: Wave, pub decay: Decay, pub tune: ModulationDepth, pub level: Level, }
impl Default for Source {
fn default() -> Self {
Source {
wave: Wave::new(),
decay: Decay::new(1),
tune: ModulationDepth::new(0),
level: Level::new(100),
}
}
}
impl fmt::Display for Source {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"wave = {} ({}), decay = {}, tune = {}, level = {}",
self.wave.name(), self.wave.number.value(),
self.decay.value(),
self.tune.value(),
self.level.value()
)
}
}
impl SystemExclusiveData for Source {
fn from_bytes(data: &[u8]) -> Result<Self, ParseError> {
Ok(Source {
wave: Wave::from_bytes(&[data[0], data[1]])?,
decay: Decay::new(data[2] as i32),
tune: ModulationDepth::new((data[3] as i32) - 50), level: Level::new(data[4] as i32),
})
}
fn to_bytes(&self) -> Vec<u8> {
let mut buf: Vec<u8> = Vec::new();
buf.extend(self.wave.to_bytes());
buf.push(self.decay.value() as u8);
buf.push((self.tune.value() + 50) as u8);
buf.push(self.level.value() as u8);
buf
}
fn data_size() -> usize { 5 }
}
#[cfg(test)]
mod tests {
use super::{*};
use crate::k4::{
bank,
sysex::Header,
single::SinglePatch,
multi::MultiPatch,
drum::DrumPatch
};
static DATA: &'static [u8] = include_bytes!("A401.SYX");
#[test]
fn test_drum_patch_from_bytes() {
let start: usize = dbg!(
2 +
Header::data_size() +
bank::SINGLE_PATCH_COUNT * SinglePatch::data_size() +
bank::MULTI_PATCH_COUNT * MultiPatch::data_size());
let patch = DrumPatch::from_bytes(&DATA[start..]);
assert_eq!(patch.unwrap().common.volume.value(), 0x64);
}
}