use crate::audio::{GenericAudioSpecs};
use super::{AudioSample, AudioBuffer,PcmConverter};
use super::super::{ErrorKind,Result};
use std::io::Read;
use std::mem;
use std::slice;
macro_rules! convert_and_copy {
( $src_type:ident, $dst_type:ident, $data_slice:ident , $convert_closure:expr ) => {{
return unsafe {
slice::from_raw_parts(
$data_slice.as_ptr() as *const AudioSample<$src_type>,
$data_slice.len() / mem::size_of::<AudioSample<$src_type>>(),
)
}
.iter()
.map(|&src_sample| {
AudioSample::from([
$convert_closure(src_sample.channel[0]),
$convert_closure(src_sample.channel[1]),
])
})
.collect();
}};
}
#[repr(C, packed)]
#[derive(Copy, Clone)]
pub struct WavHeader {
pub chunk_id: u32,
pub chunk_size: u32,
pub format: u32,
pub subchunk1_id: u32,
pub subchunk1_id_size: u32,
pub audio_format: u16,
pub num_channels: u16,
pub sample_rate: u32,
pub byte_rate: u32,
pub block_align: u16,
pub bits_per_sample: u16,
pub subchunk2_id: u32,
pub subchunk2_size: u32,
}
pub struct WavFile {
data: Option<Vec<u8>>,
header: Option<WavHeader>,
}
impl WavFile {
pub fn new() -> Self {
Self {
data: None,
header: None,
}
}
pub fn header(&self) -> Option<WavHeader> {
self.header
}
pub fn with_data(mut self, wav_data: Vec<u8>) -> Self {
self.data = Some(wav_data);
self
}
pub fn data(&self) -> Option<&Vec<u8>> {
self.data.as_ref()
}
pub fn data_mut(&mut self) -> Option<&mut Vec<u8>> {
self.data.as_mut()
}
pub fn parse(mut self) -> Result<Self> {
let res = self.data.as_ref().map(|data| {
let mut data_slice = &data[..];
let mut header_bytes = [0u8; 44];
data_slice.read(&mut header_bytes).map(|bytes_read| {
let header = *unsafe { mem::transmute::<_, &WavHeader>(header_bytes.as_ptr()) };
(header, bytes_read)
})
});
self.header = match res {
Some(Ok((header, 44))) => Some(header),
_ => {
return Err(wav_parse_error(
"File not large enough! Failed to read wav header!",
));
}
};
match &self.header {
&Some(WavHeader {
bits_per_sample,
audio_format,
..
}) => {
if bits_per_sample != 16 && bits_per_sample != 8 {
return Err(wav_parse_error(
"Only 8 and 16 bit precision pcm is supported",
));
}
if audio_format != 1 {
return Err(wav_parse_error("Only uncompressed wav files is supported"));
}
}
_ => (),
}
Ok(self)
}
}
impl GenericAudioSpecs for WavFile {
fn sample_rate(&self) -> Option<u32> {
self.header.map(|hdr| hdr.sample_rate)
}
fn bits_per_sample(&self) -> Option<u32> {
self.header.map(|hdr| hdr.bits_per_sample as u32)
}
fn channels(&self) -> Option<u32> {
self.header.map(|hdr| hdr.num_channels as u32)
}
}
impl PcmConverter<f32> for WavFile {
#[allow(unreachable_code)]
fn samples(self) -> Vec<AudioSample<f32>> {
if let Some(&header) = self.header.as_ref() {
if let Some(data_vec) = &self.data {
let data_slice = &data_vec[44..];
if header.bits_per_sample == 8 {
let convert_closure = |input| input as f32 / 255.0f32;
return convert_and_copy!(u8, f32, data_slice, convert_closure);
} else if header.bits_per_sample == 16 {
let convert_closure = |input| input as f32 / 32767.0;
return convert_and_copy!(i16, f32, data_slice, convert_closure);
}
}
}
Vec::new()
}
}
impl<T> Into<WavBuffer<T>> for Vec<AudioSample<T>> {
fn into(self) -> WavBuffer<T> {
WavBuffer {
samples: self,
sample_index: 0,
}
}
}
impl Into<WavBuffer<f32>> for WavFile {
fn into(self) -> WavBuffer<f32> {
let samples = self.samples();
WavBuffer {
samples,
sample_index: 0,
}
}
}
fn wav_parse_error(msg: &str) -> ErrorKind {
ErrorKind::WavParseError(String::from(msg))
}
#[derive(Default)]
pub struct WavBuffer<T> {
pub samples: Vec<AudioSample<T>>,
pub sample_index: usize,
}
impl AudioBuffer<f32> for WavBuffer<f32> {
fn read(&mut self, out: &mut [AudioSample<f32>]) -> usize {
if self.sample_index >= self.samples.len() {
return 0;
}
let buff = &self.samples[self.sample_index..];
let out_len = out.len();
let buff_len = buff.len();
let mut samples_read = 0;
buff.iter()
.enumerate()
.take_while(|&(i, _)| i < out_len.min(buff_len))
.for_each(|(i, &s)| {
out[i] = s;
samples_read += 1;
});
self.sample_index += samples_read;
samples_read
}
fn seek_to_start(&mut self) {
self.sample_index = 0;
}
}
impl AudioBuffer<f32> for WavBuffer<i16> {
fn read(&mut self, out: &mut [AudioSample<f32>]) -> usize {
if self.sample_index >= self.samples.len() {
return 0;
}
let buff = &self.samples[self.sample_index..];
let out_len = out.len();
let buff_len = buff.len();
let mut samples_read = 0;
buff.iter()
.enumerate()
.take_while(|&(i, _)| i < out_len.min(buff_len))
.for_each(|(i, &s)| {
out[i] = AudioSample::from([
s.channel[0] as f32 / 65535.0f32,
s.channel[1] as f32 / 65535.0f32,
]);
samples_read += 1;
});
self.sample_index += samples_read;
samples_read
}
fn seek_to_start(&mut self) {
self.sample_index = 0;
}
}