use core::f32;
use core::fmt;
use core::num::Wrapping as w;
use arrayvec::ArrayVec;
use byteorder::{ByteOrder, LittleEndian};
#[cfg(feature = "std")]
use thiserror::Error;
use crate::consts::*;
#[derive(Debug)]
#[cfg_attr(feature = "std", derive(Error))]
pub enum Error {
#[error("Incorrect file length")]
FileLength,
#[error("Invalid waveform")]
InvalidWaveform,
#[error("Invalid filter")]
InvalidFilter,
}
#[derive(Debug)]
pub struct Song {
pub(crate) instruments: [Instrument; NUM_INSTRUMENTS],
pub(crate) seq_length: usize,
pub(crate) quarter_note_length: u32,
}
pub(crate) struct Instrument {
pub(crate) osc: [Oscillator; 2],
pub(crate) noise_fader: f32,
pub(crate) env: Envelope,
pub(crate) fx: Effects,
pub(crate) lfo: LFO,
pub(crate) seq: [usize; SEQUENCE_LENGTH],
pub(crate) pat: [Pattern; NUM_PATTERNS],
}
#[derive(Debug)]
pub(crate) struct Oscillator {
pub(crate) octave: u8,
pub(crate) detune_freq: u8,
pub(crate) detune: f32,
pub(crate) envelope: bool,
pub(crate) volume: f32,
pub(crate) waveform: Waveform,
}
#[derive(Debug)]
pub(crate) struct Envelope {
pub(crate) attack: u32,
pub(crate) sustain: u32,
pub(crate) release: u32,
pub(crate) master: f32,
}
#[derive(Debug)]
pub(crate) struct Effects {
pub(crate) filter: Filter,
pub(crate) freq: f32,
pub(crate) resonance: f32,
pub(crate) delay_time: u8,
pub(crate) delay_amount: f32,
pub(crate) pan_freq: u8,
pub(crate) pan_amount: f32,
}
#[derive(Debug)]
pub(crate) struct LFO {
pub(crate) osc0_freq: bool,
pub(crate) fx_freq: bool,
pub(crate) freq: u8,
pub(crate) amount: f32,
pub(crate) waveform: Waveform,
}
#[cfg(feature = "std")]
impl fmt::Debug for Instrument {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Instrument {{ ")?;
write!(f, "osc: {:?}, ", self.osc)?;
write!(f, "env: {:?}, ", self.env)?;
write!(f, "fx: {:?}, ", self.fx)?;
write!(f, "lfo: {:?}, ", self.lfo)?;
write!(f, "pat: {:?}, ", self.pat)?;
write!(f, "seq: [")?;
let mut iter = self.seq.iter();
if let Some(i) = iter.next() {
write!(f, "{:?}", i)?;
}
for i in iter {
write!(f, ", {:?}", i)?;
}
write!(f, "] }}")
}
}
#[cfg(not(feature = "std"))]
impl fmt::Debug for Instrument {
fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
Ok(())
}
}
#[derive(Debug)]
pub(crate) struct Pattern {
pub(crate) notes: [u8; PATTERN_LENGTH],
}
#[derive(Debug)]
pub(crate) enum Filter {
None,
HighPass,
LowPass,
BandPass,
Notch,
}
#[derive(Debug)]
pub(crate) enum Waveform {
Sine,
Square,
Saw,
Triangle,
}
impl Song {
pub fn from_slice(slice: &[u8]) -> Result<Self, Error> {
if slice.len() != SONG_LENGTH {
return Err(Error::FileLength);
}
let quarter_note_length = LittleEndian::read_u32(&slice[..HEADER_LENGTH]);
let quarter_note_length = quarter_note_length - (quarter_note_length % 2);
let seq_length = slice[HEADER_LENGTH + INSTRUMENT_LENGTH * 8] as usize;
let mut instruments = ArrayVec::new();
for i in 0..NUM_INSTRUMENTS {
instruments.push(load_instrument(slice, i)?);
}
let instruments = instruments.into_inner().unwrap();
Ok(Self {
instruments,
seq_length,
quarter_note_length,
})
}
}
fn parse_waveform(waveform: u8) -> Result<Waveform, Error> {
Ok(match waveform {
0 => Waveform::Sine,
1 => Waveform::Square,
2 => Waveform::Saw,
3 => Waveform::Triangle,
_ => return Err(Error::InvalidWaveform),
})
}
fn load_oscillator(slice: &[u8], i: usize, o: usize) -> Result<Oscillator, Error> {
let i = i + o * OSCILLATOR_LENGTH;
let octave = ((w(slice[i]) - w(8)) * w(12)).0;
let detune_freq = slice[i + 1];
let detune = f32::from(slice[i + 2]).mul_add(0.2 / 255.0, 1.0);
let envelope = slice[i + 3] != 0;
let volume = f32::from(slice[i + 4]) / 255.0;
let waveform = parse_waveform(slice[i + 5])?;
Ok(Oscillator {
octave,
detune_freq,
detune,
envelope,
volume,
waveform,
})
}
fn load_envelope(slice: &[u8], i: usize) -> Envelope {
let attack = LittleEndian::read_u32(&slice[i..i + 4]);
let sustain = LittleEndian::read_u32(&slice[i + 4..i + 8]);
let release = LittleEndian::read_u32(&slice[i + 8..i + 12]);
let master = f32::from(slice[i + 12]) * 156.0;
Envelope {
attack,
sustain,
release,
master,
}
}
fn load_effects(slice: &[u8], i: usize) -> Result<Effects, Error> {
let filter = match slice[i] {
0 => Filter::None,
1 => Filter::HighPass,
2 => Filter::LowPass,
3 => Filter::BandPass,
4 => Filter::Notch,
_ => return Err(Error::InvalidFilter),
};
let i = i + 3;
let freq = f32::from_bits(LittleEndian::read_u32(&slice[i..i + 4]));
let resonance = f32::from(slice[i + 4]) / 255.0;
let delay_time = slice[i + 5];
let delay_amount = f32::from(slice[i + 6]) / 255.0;
let pan_freq = slice[i + 7];
let pan_amount = f32::from(slice[i + 8]) / 512.0;
Ok(Effects {
filter,
freq,
resonance,
delay_time,
delay_amount,
pan_freq,
pan_amount,
})
}
fn load_lfo(slice: &[u8], i: usize) -> Result<LFO, Error> {
let osc0_freq = slice[i] != 0;
let fx_freq = slice[i + 1] != 0;
let freq = slice[i + 2];
let amount = f32::from(slice[i + 3]) / 512.0;
let waveform = parse_waveform(slice[i + 4])?;
Ok(LFO {
osc0_freq,
fx_freq,
freq,
amount,
waveform,
})
}
fn load_sequence(slice: &[u8], i: usize) -> [usize; SEQUENCE_LENGTH] {
let mut seq = [0; SEQUENCE_LENGTH];
slice[i..i + SEQUENCE_LENGTH]
.iter()
.enumerate()
.for_each(|(i, &x)| {
seq[i] = x as usize;
});
seq
}
fn load_pattern(slice: &[u8], i: usize, p: usize) -> Pattern {
let i = i + p * PATTERN_LENGTH;
let mut notes = [0; PATTERN_LENGTH];
notes.copy_from_slice(&slice[i..i + PATTERN_LENGTH]);
Pattern { notes }
}
fn load_instrument(slice: &[u8], i: usize) -> Result<Instrument, Error> {
let i = HEADER_LENGTH + i * INSTRUMENT_LENGTH;
let osc = [load_oscillator(slice, i, 0)?, load_oscillator(slice, i, 1)?];
let i = i + OSCILLATOR_LENGTH * 2;
let noise_fader = f32::from(slice[i]) / 255.0;
let i = i + 4;
let env = load_envelope(slice, i);
let i = i + 13;
let fx = load_effects(slice, i)?;
let i = i + 12;
let lfo = load_lfo(slice, i)?;
let i = i + 5;
let seq = load_sequence(slice, i);
let i = i + SEQUENCE_LENGTH;
let mut pat = ArrayVec::new();
for j in 0..NUM_PATTERNS {
pat.push(load_pattern(slice, i, j));
}
let pat = pat.into_inner().unwrap();
Ok(Instrument {
osc,
noise_fader,
env,
fx,
lfo,
seq,
pat,
})
}