use crate::consts::{HEADER_LENGTH, INSTRUMENT_LENGTH, NUM_INSTRUMENTS, NUM_PATTERNS};
use crate::consts::{OSCILLATOR_LENGTH, PATTERN_LENGTH, SEQUENCE_LENGTH, SONG_LENGTH};
use arrayvec::ArrayVec;
use byteorder::{ByteOrder as _, LittleEndian};
use core::num::Wrapping as w;
#[cfg(feature = "std")]
use thiserror::Error;
#[derive(Debug)]
#[cfg_attr(feature = "std", derive(Error))]
pub enum Error {
#[cfg_attr(feature = "std", error("Incorrect file length"))]
FileLength,
#[cfg_attr(feature = "std", error("Invalid waveform"))]
InvalidWaveform,
#[cfg_attr(feature = "std", error("Invalid filter"))]
InvalidFilter,
#[cfg_attr(feature = "std", error("Invalid instruments"))]
InvalidInstruments,
}
#[derive(Debug)]
pub struct Song {
pub(crate) instruments: [Instrument; NUM_INSTRUMENTS],
pub(crate) seq_length: usize, pub(crate) quarter_note_length: u32, }
#[derive(Debug)]
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, }
#[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()
.map_err(|_| Error::InvalidInstruments)?;
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 = libm::fmaf(f32::from(slice[i + 2]), 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,
})
}