use bitflags::bitflags;
use std::fmt;
use std::fs;
use std::io;
use super::io::{AudioReader, AudioSamplesIterator, Sample, SampleFormat};
use super::{codecs, errors, Result};
use super::{wav, flac};
bitflags! {
pub struct Channels: u32 {
const FRONT_LEFT = 0x0000_0001; const FRONT_RIGHT = 0x0000_0002; const FRONT_CENTRE = 0x0000_0004;
const BACK_LEFT = 0x0000_0008;
const BACK_CENTRE = 0x0000_0010;
const BACK_RIGHT = 0x0000_0020;
const LFE1 = 0x0000_0040; const FRONT_LEFT_CENTRE = 0x0000_0080;
const FRONT_RIGHT_CENTRE = 0x0000_0100;
const BACK_LEFT_CENTRE = 0x0000_0200;
const BACK_RIGHT_CENTRE = 0x0000_0400;
const FRONT_LEFT_WIDE = 0x0000_0800;
const FRONT_RIGHT_WIDE = 0x0000_1000;
const FRONT_LEFT_HIGH = 0x0000_2000;
const FRONT_CENTRE_HIGH = 0x0000_4000;
const FRONT_RIGHT_HIGH = 0x0000_8000;
const LFE2 = 0x0001_0000; const SIDE_LEFT = 0x0002_0000;
const SIDE_RIGHT = 0x0004_0000;
const TOP_CENTRE = 0x0008_0000;
const TOP_FRONT_LEFT = 0x0010_0000;
const TOP_FRONT_CENTRE = 0x0020_0000;
const TOP_FRONT_RIGHT = 0x0040_0000;
const TOP_BACK_LEFT = 0x0080_0000;
const TOP_BACK_CENTRE = 0x0100_0000;
const TOP_BACK_RIGHT = 0x0200_0000;
}
}
impl Channels {
pub fn count(self) -> usize {
self.bits.count_ones() as usize
}
}
impl fmt::Display for Channels {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:#032b}", self.bits)
}
}
#[derive(Copy, Clone, Debug)]
pub enum ChannelLayout {
Mono,
Stereo,
TwoPointOne,
ThreePointZero,
Quad,
FivePointZero,
FivePointOne,
SixPointOne,
SixPointOneBack,
SevenPointOne,
}
impl ChannelLayout {
pub fn into_channels(self) -> Channels {
match self {
ChannelLayout::Mono => Channels::FRONT_LEFT,
ChannelLayout::Stereo => Channels::FRONT_LEFT | Channels::FRONT_RIGHT,
ChannelLayout::TwoPointOne => {
Channels::FRONT_LEFT | Channels::FRONT_RIGHT | Channels::LFE1
}
ChannelLayout::ThreePointZero => {
Channels::FRONT_LEFT | Channels::FRONT_RIGHT | Channels::FRONT_CENTRE
}
ChannelLayout::Quad => {
Channels::FRONT_LEFT
| Channels::FRONT_RIGHT | Channels::BACK_LEFT | Channels::BACK_RIGHT
}
ChannelLayout::FivePointZero => {
Channels::FRONT_LEFT
| Channels::FRONT_RIGHT | Channels::FRONT_CENTRE
| Channels::BACK_LEFT | Channels::BACK_RIGHT
}
ChannelLayout::FivePointOne => {
Channels::FRONT_LEFT
| Channels::FRONT_RIGHT | Channels::FRONT_CENTRE | Channels::LFE1
| Channels::BACK_LEFT | Channels::BACK_RIGHT
}
ChannelLayout::SixPointOne => {
Channels::FRONT_LEFT
| Channels::FRONT_RIGHT | Channels::FRONT_CENTRE | Channels::LFE1
| Channels::BACK_CENTRE | Channels::SIDE_LEFT | Channels::SIDE_RIGHT
}
ChannelLayout::SixPointOneBack => {
Channels::FRONT_LEFT
| Channels::FRONT_RIGHT | Channels::FRONT_CENTRE | Channels::LFE1
| Channels::BACK_CENTRE | Channels::BACK_LEFT | Channels::BACK_RIGHT
}
ChannelLayout::SevenPointOne => {
Channels::FRONT_LEFT
| Channels::FRONT_RIGHT | Channels::FRONT_CENTRE | Channels::LFE1
| Channels::BACK_LEFT | Channels::BACK_RIGHT
| Channels::SIDE_LEFT | Channels::SIDE_RIGHT
}
}
}
}
impl fmt::Display for ChannelLayout {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:?}", self)
}
}
#[derive(Clone, Copy)]
pub struct AudioInfo {
pub codec: codecs::CodecType,
pub audio_format: SampleFormat,
pub sample_rate: u32,
pub total_samples: u64,
pub bits_per_sample: u32,
pub channels: Channels,
pub channel_layout: ChannelLayout,
}
impl fmt::Display for AudioInfo {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "| Codec: {}\n", self.codec)?;
write!(f, "| Sample Format: {:?}\n", self.audio_format)?;
write!(f, "| Sample Rate: {}\n", self.sample_rate)?;
write!(f, "| Total Samples: {}\n", self.total_samples)?;
write!(f, "| Bits per Sample: {}\n", self.bits_per_sample)?;
write!(f, "| Channel(s): {}\n", self.channels.count())?;
write!(f, "| Channel Layout: {:?}\n", self.channel_layout)?;
Ok(())
}
}
pub struct AudioSegment {
codec_flag: codecs::CodecFlag,
info: AudioInfo,
reader: Box<dyn AudioReader>,
}
impl AudioSegment {
pub fn read(filename: &'static str, flag: codecs::CodecFlag) -> Result<AudioSegment> {
let file = fs::File::open(filename).unwrap();
let file_buffer = io::BufReader::new(file);
let mut read_res = match flag {
codecs::CodecFlag::WAV => wav::WavReader::new(file_buffer)?,
codecs::CodecFlag::FLAC => flac::FlacReader::new(file_buffer)?,
_ => return errors::unsupported_error("Codec flag not supported"),
};
Ok(AudioSegment {
codec_flag: flag,
info: read_res.read_header()?,
reader: read_res,
})
}
pub fn info(&self) -> AudioInfo {
self.info
}
pub fn number_channels(&self) -> usize {
self.info.channels.count()
}
pub fn duration(&self) -> f32 {
self.info.total_samples as f32
/ (self.number_channels() as u32 * self.info.sample_rate) as f32
}
pub fn bitrate(&self) -> u32 {
(self.info.sample_rate / 1000) * self.info.bits_per_sample * self.number_channels() as u32
}
pub fn samples<'a, S: Sample + 'a>(&'a mut self) -> Box<dyn AudioSamplesIterator<S> + 'a> {
return match self.codec_flag {
codecs::CodecFlag::WAV => wav::WavSamplesIterator::new(&mut self.reader, &self.info),
codecs::CodecFlag::FLAC => flac::FlacSamplesIterator::new(&mut self.reader, &self.info),
_ => unreachable!(),
};
}
}
impl fmt::Display for AudioSegment {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "AudioInfo:\n{}\n", self.info)?;
write!(
f,
"duration: {}s, bitrate: {}kbps",
self.duration(),
self.bitrate()
)?;
Ok(())
}
}
#[test]
fn read_wav() {
let mut au_seg = AudioSegment::read(
"samples/wav/test-16bit-44100Hz-mono.wav",
codecs::CodecFlag::WAV,
).unwrap();
assert_eq!(au_seg.number_channels(), 1);
assert_eq!(au_seg.info().sample_rate, 44100);
assert_eq!(au_seg.info().bits_per_sample, 16);
assert_eq!(au_seg.info().audio_format, SampleFormat::U16);
let samples: Vec<i16> = au_seg.samples().map(|r| r.unwrap()).collect();
assert_eq!(&samples[..], &[2, -3, 5, -7]);
}