minidsp 0.1.4

A control interface for some MiniDSP products
Documentation
use std::path::Path;

use thiserror::Error;
#[derive(Error, Debug)]
pub enum WavReadError {
    #[error("IO Error")]
    IOError(#[from] std::io::Error),
    #[error("The file didn't match the device's internal sampling rate")]
    InvalidSampleRate,
    #[error("The file didn't contain any samples")]
    NoData,
}

pub fn read_wav_filter<T: AsRef<Path>>(
    filename: T,
    sample_rate: u32,
) -> Result<Vec<f32>, WavReadError> {
    let mut inp_file = std::fs::File::open(filename)?;
    let (header, data) = ::wav::read(&mut inp_file)?;

    if header.sampling_rate != sample_rate {
        return Err(WavReadError::InvalidSampleRate);
    }

    convert_data(data)
}

fn convert_data(data: wav::BitDepth) -> Result<Vec<f32>, WavReadError> {
    let samples: Vec<f32>;

    match data {
        wav::BitDepth::Eight(data) => {
            samples = data.iter().map(|x| (*x as f32 - 128.) / 128f32).collect();
        }
        wav::BitDepth::Sixteen(data) => {
            samples = data.iter().map(|x| *x as f32 / (i16::MAX as f32)).collect();
        }
        wav::BitDepth::TwentyFour(data) => {
            samples = data
                .iter()
                .map(|x| *x as f32 / ((1 << 23) as f32))
                .collect();
        }
        wav::BitDepth::Empty => {
            return Err(WavReadError::NoData);
        }
        wav::BitDepth::ThirtyTwoFloat(data) => {
            samples = data;
        }
    }

    Ok(samples)
}

#[cfg(test)]
mod test {
    use std::vec;

    use assert_approx_eq::assert_approx_eq;
    use wav::BitDepth;

    use super::convert_data;

    #[test]
    fn test_u8() {
        let data = BitDepth::Eight(vec![0, 255, 128]);
        let expected: Vec<f32> = vec![-1.0, 1.0, 0.0];
        let samples = convert_data(data).unwrap();

        for (sample, expected) in samples.iter().zip(expected.iter()) {
            assert_approx_eq!(*sample, *expected, 1e-2);
        }
    }

    #[test]
    fn test_i16() {
        let data = BitDepth::Sixteen(vec![i16::MIN, 0, i16::MAX]);
        let expected: Vec<f32> = vec![-1.0, 0.0, 1.0];
        let samples = convert_data(data).unwrap();

        for (sample, expected) in samples.iter().zip(expected.iter()) {
            assert_approx_eq!(*sample, *expected, 1e-2);
        }
    }

    #[test]
    fn test_i24() {
        let data = BitDepth::TwentyFour(vec![-1 << 23, 0, 1 << 23]);
        let expected: Vec<f32> = vec![-1.0, 0.0, 1.0];
        let samples = convert_data(data).unwrap();

        for (sample, expected) in samples.iter().zip(expected.iter()) {
            assert_approx_eq!(*sample, *expected, 1e-2);
        }
    }
}