Something went wrong. Try again.
This repository has no description
Something went wrong. Try again.
8.5 kB · 307 lines
Rust
at sans-io
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308// look at player/csndfile.c csf_read_sample#![allow(dead_code)] // not nearly done
use std::fmt::Debug;use std::num::NonZeroU32;
use crate::{ file::{InFilePtr, err::LoadErr}, sample::VibratoWave,};
use super::header;
fn vibratowave_try_from(value: u8) -> Option<VibratoWave> { match value { 0 => Some(VibratoWave::Sine), 1 => Some(VibratoWave::RampDown), 2 => Some(VibratoWave::Square), 3 => Some(VibratoWave::Random), _ => None, }}
enum ImpulseSampleBitWidth { Seven, Eight, Sixteen, TwentyFour, ThirtyTwo,}
impl From<ImpulseSampleBitWidth> for usize { fn from(value: ImpulseSampleBitWidth) -> Self { match value { ImpulseSampleBitWidth::Seven => 7, ImpulseSampleBitWidth::Eight => 8, ImpulseSampleBitWidth::Sixteen => 16, ImpulseSampleBitWidth::TwentyFour => 24, ImpulseSampleBitWidth::ThirtyTwo => 32, } }}
enum ImpulseSampleChannels { Mono, StereoInterleaved, StereoSplit,}
enum ImpulseSampleEndianness { Little, Big,}
/// don't know what most of them are. Just took them from include/sndfile.h of schism trackerenum ImpulseSampleEncoding { PCMSigned, PCMUnsigned, PCMDelta, IT2_14Comp, IT2_15Comp, Ams, Dmf, Mdl, Ptm, PCM16,}
/// don't understand what bit 3 is supposed to do#[derive(Copy, Clone)]pub struct SampleFormatConvert(u8);
impl SampleFormatConvert { // alternative is unsigned pub fn is_signed(self) -> bool { (self.0 & 0x1) != 0 } /// should only be true for very old files (isn't even supported in C schism) pub fn is_big_endian(self) -> bool { (self.0 & 0x2) != 0 } /// alternative is PCM samples pub fn delta_samples(self) -> bool { (self.0 & 0x4) != 0 } /// not supported pub fn byte_delta(self) -> bool { (self.0 & 0x8) != 0 } /// don't support in first step pub fn tx_wave_12bit(self) -> bool { (self.0 & 0x10) != 0 } /// don't know if this also means that the sample is stereo pub fn should_show_stereo_prompt(self) -> bool { (self.0 & 0x20) != 0 }}
impl Debug for SampleFormatConvert { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("SampleFormatConvert") .field("is_signed", &self.is_signed()) .field("is_big_endian", &self.is_big_endian()) .field("delta_sample", &self.delta_samples()) .field("byte_delta", &self.byte_delta()) .field("tx_wave_12bit", &self.tx_wave_12bit()) .field( "should_show_stereo_prompt", &self.should_show_stereo_prompt(), ) .finish() }}
#[derive(Copy, Clone)]pub struct SampleFormatFlags(u8);
impl SampleFormatFlags { pub fn has_sample(self) -> bool { (self.0 & 0x01) != 0 } pub fn is_16bit(self) -> bool { (self.0 & 0x02) != 0 } pub fn is_8bit(self) -> bool { !self.is_16bit() } pub fn is_stereo(self) -> bool { (self.0 & 0x04) != 0 } pub fn is_compressed(self) -> bool { (self.0 & 0x08) != 0 } pub fn uses_loop(self) -> bool { (self.0 & 0x10) != 0 } pub fn uses_sustain_loop(self) -> bool { (self.0 & 0x20) != 0 } pub fn ping_pong_loop(self) -> bool { (self.0 & 0x40) != 0 } pub fn forward_loop(self) -> bool { !self.ping_pong_loop() } pub fn ping_pong_sustain_loop(self) -> bool { (self.0 & 0x80) != 0 } pub fn forward_sustain_loop(self) -> bool { !self.ping_pong_sustain_loop() }}
impl Debug for SampleFormatFlags { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let mut fmt = f.debug_struct("SampleFormatFlags"); fmt.field("has_sample", &self.has_sample()); fmt.field("is_16bit", &self.is_16bit()); fmt.field("is_stereo", &self.is_stereo()); fmt.field("is_compressed", &self.is_compressed()); fmt.field("uses_loop", &self.uses_loop()); fmt.field("uses_sustain_loop", &self.uses_sustain_loop()); fmt.field("ping_pong_loop", &self.ping_pong_loop()); fmt.field("ping_pong_sustain_loop", &self.ping_pong_sustain_loop()); fmt.finish() }}
#[derive(Debug)]pub struct ImpulseSampleHeader { pub dos_filename: Box<[u8]>, pub sample_name: String, pub global_volume: u8, pub flags: SampleFormatFlags, pub default_volume: u8, pub convert: SampleFormatConvert, pub default_pan: u8, // frame count pub length: u32, pub loop_start: u32, pub loop_end: u32, pub c5_speed: u32, pub sustain_start: u32, pub sustain_end: u32, pub data_ptr: InFilePtr, pub vibrato_speed: u8, pub vibrato_depth: u8, pub vibrato_type: VibratoWave, pub vibrato_rate: u8,}
impl ImpulseSampleHeader { pub const SIZE: usize = 80;
pub fn parse(buf: &[u8; Self::SIZE]) -> Result<Self, LoadErr> { if !buf.starts_with(b"IMPS") { return Err(LoadErr::Invalid); }
let dos_filename = buf[0x4..=0xF].to_vec().into_boxed_slice(); if buf[0x10] != 0 { return Err(LoadErr::Invalid); }
let global_volume = if buf[0x11] > 64 { // defect_handler(LoadDefect::OutOfBoundsValue); 64 } else { buf[0x11] };
let flags = SampleFormatFlags(buf[0x12]); let default_volume = buf[0x13]; let sample_name = { let str = buf[0x14..=0x2D].split(|b| *b == 0).next().unwrap().to_vec(); let str = String::from_utf8(str); if str.is_err() { // defect_handler(LoadDefect::InvalidText); } str.unwrap_or_default() };
let convert = SampleFormatConvert(buf[0x2E]);
let default_pan = buf[0x2F];
// in samples, not bytes let length = u32::from_le_bytes([buf[0x30], buf[0x31], buf[0x32], buf[0x33]]); let loop_start = u32::from_le_bytes([buf[0x34], buf[0x35], buf[0x36], buf[0x37]]); let loop_end = u32::from_le_bytes([buf[0x38], buf[0x39], buf[0x3A], buf[0x3B]]);
// bytes per second at c5 let c5_speed = { let speed = u32::from_le_bytes([buf[0x3C], buf[0x3D], buf[0x3E], buf[0x3F]]); if speed > 9999999 { // defect_handler(LoadDefect::OutOfBoundsValue); // no idea what is a good default here 9999999 / 2 } else { speed } };
// in samples, not bytes let sustain_start = u32::from_le_bytes([buf[0x40], buf[0x41], buf[0x42], buf[0x43]]); let sustain_end = u32::from_le_bytes([buf[0x44], buf[0x45], buf[0x46], buf[0x47]]);
let data_ptr = { let value = u32::from_le_bytes([buf[0x48], buf[0x49], buf[0x4A], buf[0x4B]]); if value < header::ImpulseHeader::BASE_SIZE as u32 { return Err(LoadErr::Invalid); } InFilePtr(NonZeroU32::new(value).unwrap()) };
let vibrato_speed = if buf[0x4C] > 64 { // defect_handler(LoadDefect::OutOfBoundsValue); 32 } else { buf[0x4C] };
let vibrato_depth = if buf[0x4D] > 64 { // defect_handler(LoadDefect::OutOfBoundsValue); 32 } else { buf[0x4D] };
let vibrato_rate = if buf[0x4E] > 64 { // defect_handler(LoadDefect::OutOfBoundsValue); 32 } else { buf[0x4E] };
let vibrato_type = { let wave = vibratowave_try_from(buf[0x4F]); if wave.is_none() { // defect_handler(LoadDefect::OutOfBoundsValue); } wave.unwrap_or_default() };
Ok(Self { dos_filename, sample_name, global_volume, flags, default_volume, convert, default_pan, length, loop_start, loop_end, c5_speed, sustain_start, sustain_end, data_ptr, vibrato_speed, vibrato_depth, vibrato_type, vibrato_rate, }) }}