use super::{AudioReader, AudioWriter};
use crate::buffer::{AudioBufferIn, AudioBufferOut};
use dasp_sample::conv::{FromSample, ToSample};
use hound::{WavReader, WavSamples, WavWriter};
use std::error::Error;
use std::fmt::{Display, Formatter};
use std::io::{Read, Seek, Write};
pub struct HoundAudioReader<'wr, S>
where
S: FromSample<f32> + FromSample<i32> + FromSample<i16>,
{
hound_sample_reader: Box<dyn HoundSampleReader<S> + 'wr>,
number_of_channels: usize,
frames_per_second: u64,
}
#[derive(Debug)]
pub enum HoundAudioError {
UnsupportedAudioFormat,
}
impl Display for HoundAudioError {
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
write!(f, "Unsupported audio format")
}
}
impl Error for HoundAudioError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
None
}
}
impl<'wr, S> HoundAudioReader<'wr, S>
where
S: FromSample<f32> + FromSample<i32> + FromSample<i16>,
{
fn reader<R: Read>(
r: &'wr mut WavReader<R>,
) -> Result<Box<dyn HoundSampleReader<S> + 'wr>, HoundAudioError> {
let spec = r.spec();
Ok(match spec.sample_format {
hound::SampleFormat::Float => match spec.bits_per_sample {
32 => Box::new(F32SampleReader {
samples: r.samples(),
}),
_ => {
return Err(HoundAudioError::UnsupportedAudioFormat);
}
},
hound::SampleFormat::Int => match spec.bits_per_sample {
24 | 32 => Box::new(I32SampleReader {
samples: r.samples(),
}),
8 | 16 => Box::new(I16SampleReader {
samples: r.samples(),
}),
_ => {
return Err(HoundAudioError::UnsupportedAudioFormat);
}
},
})
}
pub fn new<R: Read>(reader: &'wr mut WavReader<R>) -> Result<Self, HoundAudioError> {
let spec = reader.spec();
let number_of_channels = spec.channels as usize;
let hound_sample_reader = Self::reader(reader)?;
Ok(Self {
number_of_channels,
frames_per_second: spec.sample_rate as u64,
hound_sample_reader,
})
}
}
impl<'wr, S> AudioReader<S> for HoundAudioReader<'wr, S>
where
S: Copy + FromSample<f32> + FromSample<i32> + FromSample<i16>,
{
type Err = hound::Error;
fn number_of_channels(&self) -> usize {
self.number_of_channels
}
fn frames_per_second(&self) -> u64 {
self.frames_per_second
}
fn fill_buffer(&mut self, outputs: &mut AudioBufferOut<S>) -> Result<usize, Self::Err> {
assert_eq!(outputs.number_of_channels(), self.number_of_channels());
let length = outputs.number_of_frames();
let mut frame_index = 0;
while frame_index < length {
for output in outputs.channel_iter_mut() {
if let Some(sample) = self.hound_sample_reader.read_sample()? {
output[frame_index] = sample;
} else {
return Ok(frame_index);
}
}
frame_index += 1;
}
Ok(frame_index)
}
}
trait HoundSampleReader<S> {
fn read_sample(&mut self) -> Result<Option<S>, hound::Error>;
}
struct F32SampleReader<'wr, R: Read> {
samples: WavSamples<'wr, R, f32>,
}
impl<'wr, R: Read, S> HoundSampleReader<S> for F32SampleReader<'wr, R>
where
S: FromSample<f32>,
{
fn read_sample(&mut self) -> Result<Option<S>, hound::Error> {
if let Some(n) = self.samples.next() {
Ok(Some(S::from_sample_(n?)))
} else {
Ok(None)
}
}
}
struct I32SampleReader<'wr, R: Read> {
samples: WavSamples<'wr, R, i32>,
}
impl<'wr, R: Read, S> HoundSampleReader<S> for I32SampleReader<'wr, R>
where
S: FromSample<i32>,
{
fn read_sample(&mut self) -> Result<Option<S>, hound::Error> {
if let Some(n) = self.samples.next() {
Ok(Some(S::from_sample_(n?)))
} else {
Ok(None)
}
}
}
struct I16SampleReader<'wr, R: Read> {
samples: WavSamples<'wr, R, i16>,
}
impl<'wr, R: Read, S> HoundSampleReader<S> for I16SampleReader<'wr, R>
where
S: FromSample<i16>,
{
fn read_sample(&mut self) -> Result<Option<S>, hound::Error> {
if let Some(n) = self.samples.next() {
Ok(Some(S::from_sample_(n?)))
} else {
Ok(None)
}
}
}
pub struct HoundAudioWriter<'ww, S>
where
S: ToSample<f32> + ToSample<i32> + ToSample<i16>,
{
hound_sample_writer: Box<dyn HoundSampleWriter<S> + 'ww>,
number_of_channels: usize,
}
impl<'ww, S> HoundAudioWriter<'ww, S>
where
S: ToSample<f32> + ToSample<i32> + ToSample<i16>,
{
fn hound_sample_writer<W: Write + Seek>(
writer: &'ww mut WavWriter<W>,
) -> Result<Box<dyn HoundSampleWriter<S> + 'ww>, HoundAudioError> {
let spec = writer.spec();
Ok(match spec.sample_format {
hound::SampleFormat::Float => match spec.bits_per_sample {
32 => Box::new(F32SampleWriter { writer }),
_ => {
return Err(HoundAudioError::UnsupportedAudioFormat);
}
},
hound::SampleFormat::Int => match spec.bits_per_sample {
22 | 32 => Box::new(I32SampleWriter { writer }),
8 | 16 => Box::new(I16SampleWriter { writer }),
_ => {
return Err(HoundAudioError::UnsupportedAudioFormat);
}
},
})
}
pub fn new<W: Write + Seek>(writer: &'ww mut WavWriter<W>) -> Result<Self, HoundAudioError> {
let spec = writer.spec();
let hound_sample_writer = Self::hound_sample_writer(writer)?;
Ok(Self {
hound_sample_writer,
number_of_channels: spec.channels as usize,
})
}
}
impl<'ww, S> AudioWriter<S> for HoundAudioWriter<'ww, S>
where
S: ToSample<f32> + ToSample<i32> + ToSample<i16> + Copy,
{
type Err = hound::Error;
fn write_buffer(&mut self, inputs: &AudioBufferIn<S>) -> Result<(), Self::Err> {
assert_eq!(inputs.number_of_channels(), self.number_of_channels);
assert!(self.number_of_channels > 0);
let length = inputs.number_of_frames();
let mut frame_index = 0;
while frame_index < length {
for input in inputs.channels().iter() {
self.hound_sample_writer.write_sample(input[frame_index])?;
}
frame_index += 1;
}
self.hound_sample_writer.flush()
}
fn specifies_number_of_channels(&self) -> bool {
true
}
fn number_of_channels(&self) -> usize {
self.number_of_channels
}
}
trait HoundSampleWriter<S> {
fn write_sample(&mut self, sample: S) -> Result<(), hound::Error>;
fn flush(&mut self) -> Result<(), hound::Error>;
}
struct F32SampleWriter<'ww, W>
where
W: Write + Seek,
{
writer: &'ww mut WavWriter<W>,
}
impl<'ww, S, W> HoundSampleWriter<S> for F32SampleWriter<'ww, W>
where
S: ToSample<f32>,
W: Write + Seek,
{
fn write_sample(&mut self, sample: S) -> Result<(), hound::Error> {
self.writer.write_sample::<f32>(sample.to_sample_())
}
fn flush(&mut self) -> Result<(), hound::Error> {
self.writer.flush()
}
}
struct I32SampleWriter<'ww, W>
where
W: Write + Seek,
{
writer: &'ww mut WavWriter<W>,
}
impl<'ww, S, W> HoundSampleWriter<S> for I32SampleWriter<'ww, W>
where
S: ToSample<i32>,
W: Write + Seek,
{
fn write_sample(&mut self, sample: S) -> Result<(), hound::Error> {
self.writer.write_sample::<i32>(sample.to_sample_())
}
fn flush(&mut self) -> Result<(), hound::Error> {
self.writer.flush()
}
}
struct I16SampleWriter<'ww, W>
where
W: Write + Seek,
{
writer: &'ww mut WavWriter<W>,
}
impl<'ww, S, W> HoundSampleWriter<S> for I16SampleWriter<'ww, W>
where
S: ToSample<i16>,
W: Write + Seek,
{
fn write_sample(&mut self, sample: S) -> Result<(), hound::Error> {
self.writer.write_sample::<i16>(sample.to_sample_())
}
fn flush(&mut self) -> Result<(), hound::Error> {
self.writer.flush()
}
}