use core::fmt::{Debug, Display};
use std::{num::NonZeroUsize, path::Path, time::Duration};
use crate::{
error::{AudioIOError, AudioIOResult},
types::{AudioInfo, BaseAudioInfo, FileType, OpenOptions, ValidatedSampleType},
};
use audio_samples::{AudioSamples, ConvertFrom, ConvertTo, SampleType, traits::StandardSample};
pub trait AudioInfoMarker {}
pub trait SpecificAudioInfo: Debug + Display + Send + Sync {
fn specific_info(&self) -> impl AudioInfoMarker;
}
pub trait AudioFileMetadata {
fn open_metadata<P: AsRef<Path>>(path: P) -> AudioIOResult<Self>
where
Self: Sized;
fn base_info(&self) -> AudioIOResult<BaseAudioInfo>;
fn specific_info(&self) -> impl AudioInfoMarker;
fn info(&self) -> AudioIOResult<AudioInfo<impl AudioInfoMarker>> {
let fp = self.file_path().to_path_buf();
let base_info = self.base_info()?;
let specific_info = self.specific_info();
Ok(AudioInfo {
fp,
base_info,
specific_info,
})
}
fn file_type(&self) -> FileType;
fn file_path(&self) -> &Path;
fn total_samples(&self) -> usize;
fn duration(&self) -> AudioIOResult<Duration>;
fn samples_per_channel(&self) -> AudioIOResult<usize> {
let base = self.base_info()?;
if base.channels > 0 {
Ok(self.total_samples() / base.channels as usize)
} else {
Err(AudioIOError::corrupted_data_simple(
"Invalid channel count in audio file",
base.channels.to_string(),
))
}
}
fn sample_type(&self) -> ValidatedSampleType;
fn num_channels(&self) -> u16;
}
pub trait AudioFile {
fn open<P: AsRef<Path>>(fp: P) -> AudioIOResult<Self>
where
Self: Sized,
{
AudioFile::open_with_options(fp, OpenOptions::default())
}
fn open_with_options<P: AsRef<Path>>(fp: P, options: OpenOptions) -> AudioIOResult<Self>
where
Self: Sized;
fn len(&self) -> u64;
fn is_empty(&self) -> bool {
self.len() == 0
}
}
pub trait AudioFileRead<'a> {
fn read<T>(&'a self) -> AudioIOResult<AudioSamples<'a, T>>
where
T: StandardSample + 'static;
fn read_into<T>(&'a self, audio: &mut AudioSamples<'a, T>) -> AudioIOResult<()>
where
T: StandardSample + 'static;
}
pub trait AudioFileWrite: AudioFile {
fn write<P, T>(&mut self, out_fp: P) -> AudioIOResult<()>
where
P: AsRef<Path>,
T: StandardSample + 'static;
}
pub trait SupportsSampleTypes<const N: usize>: AudioFile {
const SUPPORTED_SAMPLE_TYPES: [SampleType; N];
fn supports_sample_type(sample_type: SampleType) -> bool {
Self::SUPPORTED_SAMPLE_TYPES.contains(&sample_type)
}
}
pub trait AudioStreamReader {
fn current_frame(&self) -> usize;
fn remaining_frames(&self) -> usize;
fn total_frames(&self) -> usize;
fn sample_rate(&self) -> u32;
fn bytes_per_frame(&self) -> usize;
fn seek_to_frame(&mut self, frame: usize) -> AudioIOResult<()>;
fn reset(&mut self) -> AudioIOResult<()>;
}
pub trait AudioStreamRead: AudioStreamReader + AudioFileMetadata {
fn read_frames_into<T>(
&mut self,
buffer: &mut AudioSamples<'_, T>,
frame_count: NonZeroUsize,
) -> AudioIOResult<usize>
where
T: StandardSample + ConvertTo<T> + ConvertFrom<T> + 'static;
}
pub trait AudioStreamWriter {
fn flush(&mut self) -> AudioIOResult<()>;
fn finalize(&mut self) -> AudioIOResult<()>;
fn is_finalized(&self) -> bool;
fn frames_written(&self) -> usize;
fn sample_rate(&self) -> u32;
fn num_channels(&self) -> u16;
}
pub trait AudioStreamWrite: AudioStreamWriter {
fn write_frames<T>(&mut self, samples: &AudioSamples<'_, T>) -> AudioIOResult<usize>
where
T: StandardSample + ConvertTo<T> + ConvertFrom<T> + 'static;
}