+//! Sound format conversion.
+//!
+//! This module implements the functionality for conversion between different sound formats: packed or planar audio, 8-/16-/24-/32-bit, integer or floating point, different number of channels.
+//! Eventually this might support resampling as well.
pub use crate::formats::{NASoniton,NAChannelMap};
pub use crate::frame::{NAAudioBuffer,NAAudioInfo,NABufferType};
use crate::formats::NAChannelType;
use crate::frame::alloc_audio_buffer;
use crate::io::byteio::*;
+use crate::io::bitreader::*;
use std::f32::consts::SQRT_2;
+mod resample;
+pub use resample::NAResample;
+
+/// A list specifying general sound conversion errors.
#[derive(Clone,Copy,Debug,PartialEq)]
pub enum SoundConvertError {
+ /// Invalid input arguments.
InvalidInput,
+ /// Allocation failed.
AllocError,
+ /// Requested feature is not supported.
Unsupported,
}
Passthrough,
Reorder(Vec<usize>),
Remix(Vec<f32>),
+ DupMono(Vec<bool>),
}
impl ChannelOp {
fn is_remix(&self) -> bool {
- match *self {
- ChannelOp::Remix(_) => true,
- _ => false,
- }
+ matches! (*self, ChannelOp::Remix(_) | ChannelOp::DupMono(_))
}
}
-fn apply_channel_op<T:Copy>(ch_op: &ChannelOp, src: &Vec<T>, dst: &mut Vec<T>) {
+fn apply_channel_op<T:Copy>(ch_op: &ChannelOp, src: &[T], dst: &mut [T]) {
match *ch_op {
ChannelOp::Passthrough => {
- dst.copy_from_slice(src.as_slice());
+ dst.copy_from_slice(src);
},
ChannelOp::Reorder(ref reorder) => {
for (out, idx) in dst.iter_mut().zip(reorder.iter()) {
};
}
-fn remix_i32(ch_op: &ChannelOp, src: &Vec<i32>, dst: &mut Vec<i32>) {
+fn remix_i32(ch_op: &ChannelOp, src: &[i32], dst: &mut [i32]) {
if let ChannelOp::Remix(ref remix_mat) = ch_op {
let sch = src.len();
for (out, coeffs) in dst.iter_mut().zip(remix_mat.chunks(sch)) {
*out = sum as i32;
}
}
+ if let ChannelOp::DupMono(ref dup_mat) = ch_op {
+ let src = src[0];
+ for (out, copy) in dst.iter_mut().zip(dup_mat.iter()) {
+ *out = if *copy { src } else { 0 };
+ }
+ }
}
-fn remix_f32(ch_op: &ChannelOp, src: &Vec<f32>, dst: &mut Vec<f32>) {
+fn remix_f32(ch_op: &ChannelOp, src: &[f32], dst: &mut [f32]) {
if let ChannelOp::Remix(ref remix_mat) = ch_op {
let sch = src.len();
for (out, coeffs) in dst.iter_mut().zip(remix_mat.chunks(sch)) {
*out = sum;
}
}
-}
-
-fn read_samples<T:Copy>(src: &NAAudioBuffer<T>, mut idx: usize, dst: &mut Vec<T>) {
- let stride = src.get_stride();
- let data = src.get_data();
- for out in dst.iter_mut() {
- *out = data[idx];
- idx += stride;
+ if let ChannelOp::DupMono(ref dup_mat) = ch_op {
+ let src = src[0];
+ for (out, copy) in dst.iter_mut().zip(dup_mat.iter()) {
+ *out = if *copy { src } else { 0.0 };
+ }
}
}
fn cvt_from(val: u8) -> u8 { val }
}
impl FromFmt<u8> for i16 {
- fn cvt_from(val: u8) -> i16 { ((val as i16) - 128) * 0x101 }
+ fn cvt_from(val: u8) -> i16 { u16::from(val ^ 0x80).wrapping_mul(0x101) as i16}
}
impl FromFmt<u8> for i32 {
- fn cvt_from(val: u8) -> i32 { ((val as i32) - 128) * 0x01010101 }
+ fn cvt_from(val: u8) -> i32 { u32::from(val ^ 0x80).wrapping_mul(0x01010101) as i32 }
}
impl FromFmt<u8> for f32 {
- fn cvt_from(val: u8) -> f32 { ((val as f32) - 128.0) / 128.0 }
+ fn cvt_from(val: u8) -> f32 { (f32::from(val) - 128.0) / 128.0 }
}
impl FromFmt<i16> for u8 {
fn cvt_from(val: i16) -> i16 { val }
}
impl FromFmt<i16> for i32 {
- fn cvt_from(val: i16) -> i32 { (val as i32) * 0x10001 }
+ fn cvt_from(val: i16) -> i32 { (i32::from(val) & 0xFFFF) | (i32::from(val) << 16) }
}
impl FromFmt<i16> for f32 {
- fn cvt_from(val: i16) -> f32 { (val as f32) / 32768.0 }
+ fn cvt_from(val: i16) -> f32 { f32::from(val) / 32768.0 }
}
impl FromFmt<i32> for u8 {
fn cvt_from(val: f32) -> u8 { ((val * 128.0) + 128.0).min(255.0).max(0.0) as u8 }
}
impl FromFmt<f32> for i16 {
- fn cvt_from(val: f32) -> i16 { (val * 32768.0).min(16383.0).max(-16384.0) as i16 }
+ fn cvt_from(val: f32) -> i16 { (val * 32768.0).min(32767.0).max(-32768.0) as i16 }
}
impl FromFmt<f32> for i32 {
- fn cvt_from(val: f32) -> i32 { (val * 31.0f32.exp2()) as i32 }
+ fn cvt_from(val: f32) -> i32 {
+ if val >= 1.0 {
+ std::i32::MAX
+ } else if val <= -1.0 {
+ std::i32::MIN
+ } else {
+ let scale = (1u32 << 31) as f32;
+ (val * scale) as i32
+ }
+ }
}
impl FromFmt<f32> for f32 {
fn cvt_from(val: f32) -> f32 { val }
}
-fn read_samples_i32<T:Copy>(src: &NAAudioBuffer<T>, mut idx: usize, dst: &mut Vec<i32>) where i32: FromFmt<T> {
- let stride = src.get_stride();
- let data = src.get_data();
- for out in dst.iter_mut() {
- *out = i32::cvt_from(data[idx]);
- idx += stride;
+trait SampleReader {
+ fn get_samples_i32(&self, pos: usize, dst: &mut [i32]);
+ fn get_samples_f32(&self, pos: usize, dst: &mut [f32]);
+}
+
+struct GenericSampleReader<'a, T:Copy> {
+ data: &'a [T],
+ stride: usize,
+}
+
+impl<'a, T:Copy+IntoFmt<i32>+IntoFmt<f32>> SampleReader for GenericSampleReader<'a, T> {
+ fn get_samples_i32(&self, pos: usize, dst: &mut [i32]) {
+ let mut off = pos;
+ for el in dst.iter_mut() {
+ *el = self.data[off].cvt_into();
+ off += self.stride;
+ }
+ }
+ fn get_samples_f32(&self, pos: usize, dst: &mut [f32]) {
+ let mut off = pos;
+ for el in dst.iter_mut() {
+ *el = self.data[off].cvt_into();
+ off += self.stride;
+ }
}
}
-fn read_samples_f32<T:Copy>(src: &NAAudioBuffer<T>, mut idx: usize, dst: &mut Vec<f32>) where f32: FromFmt<T> {
- let stride = src.get_stride();
- let data = src.get_data();
- for out in dst.iter_mut() {
- *out = f32::cvt_from(data[idx]);
- idx += stride;
+struct S8SampleReader<'a> {
+ data: &'a [u8],
+ stride: usize,
+}
+
+impl<'a> SampleReader for S8SampleReader<'a> {
+ fn get_samples_i32(&self, pos: usize, dst: &mut [i32]) {
+ let mut off = pos;
+ for el in dst.iter_mut() {
+ *el = (self.data[off] ^ 0x80).cvt_into();
+ off += self.stride;
+ }
+ }
+ fn get_samples_f32(&self, pos: usize, dst: &mut [f32]) {
+ let mut off = pos;
+ for el in dst.iter_mut() {
+ *el = (self.data[off] ^ 0x80).cvt_into();
+ off += self.stride;
+ }
}
}
-fn read_packed<T:Copy>(src: &NAAudioBuffer<u8>, idx: usize, dst: &mut Vec<T>, fmt: &NASoniton) where u8: IntoFmt<T>, i16: IntoFmt<T>, i32: IntoFmt<T>, f32: IntoFmt<T> {
- if (fmt.bits & 7) != 0 { unimplemented!(); }
- let bytes = (fmt.bits >> 3) as usize;
- let mut offset = idx * bytes * dst.len();
- let data = src.get_data();
+struct PackedSampleReader<'a> {
+ data: &'a [u8],
+ fmt: NASoniton,
+ bpp: usize,
+}
- for el in dst.iter_mut() {
- let src = &data[offset..];
- *el = if !fmt.float {
- match (bytes, fmt.be) {
- (1, _) => src[0].cvt_into(),
- (2, true) => (read_u16be(src).unwrap() as i16).cvt_into(),
- (2, false) => (read_u16le(src).unwrap() as i16).cvt_into(),
- (3, true) => ((read_u24be(src).unwrap() << 8) as i32).cvt_into(),
- (3, false) => ((read_u24be(src).unwrap() << 8) as i32).cvt_into(),
- (4, true) => (read_u32be(src).unwrap() as i32).cvt_into(),
- (4, false) => (read_u32be(src).unwrap() as i32).cvt_into(),
- _ => unreachable!(),
+impl<'a> PackedSampleReader<'a> {
+ fn new(data: &'a [u8], fmt: NASoniton) -> Self {
+ let bpp = (fmt.bits >> 3) as usize;
+ Self { data, fmt, bpp }
+ }
+ fn get_samples<T:Copy>(&self, pos: usize, dst: &mut [T]) where u8: IntoFmt<T>, i16: IntoFmt<T>, i32: IntoFmt<T>, f32: IntoFmt<T> {
+ if (self.fmt.bits & 7) != 0 {
+ let mode = if self.fmt.be { BitReaderMode::BE } else { BitReaderMode::LE };
+ let mut br = BitReader::new(self.data, mode);
+ let offset = pos * (self.fmt.bits as usize) * dst.len();
+
+ if br.skip(offset as u32).is_ok() {
+ for el in dst.iter_mut() {
+ if self.fmt.bits < 16 {
+ *el = ((br.read(self.fmt.bits).unwrap_or(0) as i16) << (16 - self.fmt.bits)).cvt_into();
+ } else {
+ *el = ((br.read(self.fmt.bits).unwrap_or(0) as i32) << (32 - self.fmt.bits)).cvt_into();
+ }
}
} else {
- match (bytes, fmt.be) {
- (4, true) => read_f32be(src).unwrap().cvt_into(),
- (4, false) => read_f32le(src).unwrap().cvt_into(),
- (8, true) => (read_f64be(src).unwrap() as f32).cvt_into(),
- (8, false) => (read_f64le(src).unwrap() as f32).cvt_into(),
- (_, _) => unreachable!(),
+ for el in dst.iter_mut() {
+ *el = 0i16.cvt_into();
}
- };
- offset += bytes;
- }
-}
-
-fn store_samples<T:Copy, U:Copy>(dst: &mut NAAudioBuffer<T>, mut idx: usize, src: &Vec<U>) where U: IntoFmt<T> {
- let stride = dst.get_stride();
- let data = dst.get_data_mut().unwrap();
- for src_el in src.iter() {
- data[idx] = (*src_el).cvt_into();
- idx += stride;
- }
-}
-
-fn store_packed<T:Copy>(dst: &mut NAAudioBuffer<u8>, idx: usize, src: &Vec<T>, fmt: &NASoniton) where u8: FromFmt<T>, i16: FromFmt<T>, i32: FromFmt<T>, f32: FromFmt<T> {
- if (fmt.bits & 7) != 0 { unimplemented!(); }
- let bytes = (fmt.bits >> 3) as usize;
- let mut offset = idx * bytes * src.len();
- let data = dst.get_data_mut().unwrap();
-
- for el in src.iter() {
- let dst = &mut data[offset..];
- if !fmt.float {
- match (bytes, fmt.be) {
- (1, _) => {
- dst[0] = u8::cvt_from(*el);
- },
- (2, true) => write_u16be(dst, i16::cvt_from(*el) as u16).unwrap(),
- (2, false) => write_u16le(dst, i16::cvt_from(*el) as u16).unwrap(),
- (3, true) => write_u24be(dst, (i32::cvt_from(*el) >> 8) as u32).unwrap(),
- (3, false) => write_u24le(dst, (i32::cvt_from(*el) >> 8) as u32).unwrap(),
- (4, true) => write_u32be(dst, i32::cvt_from(*el) as u32).unwrap(),
- (4, false) => write_u32le(dst, i32::cvt_from(*el) as u32).unwrap(),
- _ => unreachable!(),
- };
- } else {
- match (bytes, fmt.be) {
- (4, true) => write_f32be(dst, f32::cvt_from(*el)).unwrap(),
- (4, false) => write_f32le(dst, f32::cvt_from(*el)).unwrap(),
- (8, true) => write_f64be(dst, f32::cvt_from(*el) as f64).unwrap(),
- (8, false) => write_f64le(dst, f32::cvt_from(*el) as f64).unwrap(),
- (_, _) => unreachable!(),
- };
+ }
+
+ return;
}
- offset += bytes;
+
+ let mut offset = pos * self.bpp * dst.len();
+
+ for el in dst.iter_mut() {
+ let src = &self.data[offset..];
+ *el = if !self.fmt.float {
+ match (self.bpp, self.fmt.be) {
+ (1, _) => if !self.fmt.signed { src[0].cvt_into() } else { (src[0] ^ 0x80).cvt_into() },
+ (2, true) => (read_u16be(src).unwrap() as i16).cvt_into(),
+ (2, false) => (read_u16le(src).unwrap() as i16).cvt_into(),
+ (3, true) => ((read_u24be(src).unwrap() << 8) as i32).cvt_into(),
+ (3, false) => ((read_u24be(src).unwrap() << 8) as i32).cvt_into(),
+ (4, true) => (read_u32be(src).unwrap() as i32).cvt_into(),
+ (4, false) => (read_u32be(src).unwrap() as i32).cvt_into(),
+ _ => unreachable!(),
+ }
+ } else {
+ match (self.bpp, self.fmt.be) {
+ (4, true) => read_f32be(src).unwrap().cvt_into(),
+ (4, false) => read_f32le(src).unwrap().cvt_into(),
+ (8, true) => (read_f64be(src).unwrap() as f32).cvt_into(),
+ (8, false) => (read_f64le(src).unwrap() as f32).cvt_into(),
+ (_, _) => unreachable!(),
+ }
+ };
+ offset += self.bpp;
+ }
+ }
+}
+
+impl SampleReader for PackedSampleReader<'_> {
+ fn get_samples_i32(&self, pos: usize, dst: &mut [i32]) {
+ self.get_samples(pos, dst);
+ }
+ fn get_samples_f32(&self, pos: usize, dst: &mut [f32]) {
+ self.get_samples(pos, dst);
+ }
+}
+
+trait SampleWriter {
+ fn store_samples_i32(&mut self, pos: usize, src: &[i32]);
+ fn store_samples_f32(&mut self, pos: usize, src: &[f32]);
+}
+
+struct GenericSampleWriter<'a, T:Copy> {
+ data: &'a mut [T],
+ stride: usize,
+}
+
+impl<'a, T:Copy+FromFmt<i32>+FromFmt<f32>> SampleWriter for GenericSampleWriter<'a, T> {
+ fn store_samples_i32(&mut self, pos: usize, src: &[i32]) {
+ let mut off = pos;
+ for el in src.iter() {
+ self.data[off] = (*el).cvt_into();
+ off += self.stride;
+ }
+ }
+ fn store_samples_f32(&mut self, pos: usize, src: &[f32]) {
+ let mut off = pos;
+ for el in src.iter() {
+ self.data[off] = (*el).cvt_into();
+ off += self.stride;
+ }
+ }
+}
+
+struct PackedSampleWriter<'a> {
+ data: &'a mut [u8],
+ fmt: NASoniton,
+ bpp: usize,
+}
+
+impl<'a> PackedSampleWriter<'a> {
+ fn new(data: &'a mut [u8], fmt: NASoniton) -> Self {
+ if (fmt.bits & 7) != 0 { unimplemented!(); }
+ let bpp = (fmt.bits >> 3) as usize;
+ Self { data, fmt, bpp }
+ }
+
+ fn store_samples<T:Copy>(&mut self, pos: usize, src: &[T]) where u8: FromFmt<T>, i16: FromFmt<T>, i32: FromFmt<T>, f32: FromFmt<T> {
+ let mut offset = pos * self.bpp * src.len();
+ for el in src.iter() {
+ let dst = &mut self.data[offset..];
+ if !self.fmt.float {
+ match (self.bpp, self.fmt.be) {
+ (1, _) => {
+ dst[0] = u8::cvt_from(*el);
+ if self.fmt.signed {
+ dst[0] ^= 0x80;
+ }
+ },
+ (2, true) => write_u16be(dst, i16::cvt_from(*el) as u16).unwrap(),
+ (2, false) => write_u16le(dst, i16::cvt_from(*el) as u16).unwrap(),
+ (3, true) => write_u24be(dst, (i32::cvt_from(*el) >> 8) as u32).unwrap(),
+ (3, false) => write_u24le(dst, (i32::cvt_from(*el) >> 8) as u32).unwrap(),
+ (4, true) => write_u32be(dst, i32::cvt_from(*el) as u32).unwrap(),
+ (4, false) => write_u32le(dst, i32::cvt_from(*el) as u32).unwrap(),
+ _ => unreachable!(),
+ };
+ } else {
+ match (self.bpp, self.fmt.be) {
+ (4, true) => write_f32be(dst, f32::cvt_from(*el)).unwrap(),
+ (4, false) => write_f32le(dst, f32::cvt_from(*el)).unwrap(),
+ (8, true) => write_f64be(dst, f64::from(f32::cvt_from(*el))).unwrap(),
+ (8, false) => write_f64le(dst, f64::from(f32::cvt_from(*el))).unwrap(),
+ (_, _) => unreachable!(),
+ };
+ }
+ offset += self.bpp;
+ }
+ }
+}
+
+impl SampleWriter for PackedSampleWriter<'_> {
+ fn store_samples_i32(&mut self, pos: usize, src: &[i32]) {
+ self.store_samples(pos, src);
+ }
+ fn store_samples_f32(&mut self, pos: usize, src: &[f32]) {
+ self.store_samples(pos, src);
}
}
-pub fn convert_audio_frame(src: &NABufferType, dst_info: &NAAudioInfo, dst_chmap: &NAChannelMap) ->
+/// Converts input audio buffer into desired format and returns a newly allocated buffer.
+pub fn convert_audio_frame(src: &NABufferType, dst_info: &NAAudioInfo, dst_chmap: &NAChannelMap) ->
Result<NABufferType, SoundConvertError> {
let nsamples = src.get_audio_length();
if nsamples == 0 {
}
let src_chmap = src.get_chmap().unwrap();
let src_info = src.get_audio_info().unwrap();
+ if src_info.sample_rate != dst_info.sample_rate {
+ return Err(SoundConvertError::Unsupported);
+ }
if (src_chmap.num_channels() == 0) || (dst_chmap.num_channels() == 0) {
return Err(SoundConvertError::InvalidInput);
}
} else if needs_reorder {
let reorder_mat = calculate_reorder_matrix(src_chmap, dst_chmap);
ChannelOp::Reorder(reorder_mat)
- } else {
+ } else if src_chmap.num_channels() > 1 {
let remix_mat = calculate_remix_matrix(src_chmap, dst_chmap);
ChannelOp::Remix(remix_mat)
+ } else {
+ let mut dup_mat: Vec<bool> = Vec::with_capacity(dst_chmap.num_channels());
+ for i in 0..dst_chmap.num_channels() {
+ let ch = dst_chmap.get_channel(i);
+ if ch.is_left() || ch.is_right() || ch == NAChannelType::C {
+ dup_mat.push(true);
+ } else {
+ dup_mat.push(false);
+ }
+ }
+ ChannelOp::DupMono(dup_mat)
};
let src_fmt = src_info.get_format();
return Ok(src.clone());
}
- let ret = alloc_audio_buffer(dst_info.clone(), nsamples, dst_chmap.clone());
+ let ret = alloc_audio_buffer(*dst_info, nsamples, dst_chmap.clone());
if ret.is_err() {
return Err(SoundConvertError::AllocError);
}
let mut dst_buf = ret.unwrap();
- if no_conversion {
- match (src, &mut dst_buf) {
- (NABufferType::AudioU8(sb), NABufferType::AudioU8(ref mut db)) => {
- let mut svec = vec![0; src_chmap.num_channels()];
- let mut tvec1 = vec![0; src_chmap.num_channels()];
- let mut tvec2 = vec![0; dst_chmap.num_channels()];
- let mut dvec = vec![0; dst_chmap.num_channels()];
- for i in 0..nsamples {
- read_samples(sb, i, &mut svec);
- if !channel_op.is_remix() {
- apply_channel_op(&channel_op, &svec, &mut dvec);
- } else {
- for (oel, iel) in tvec1.iter_mut().zip(svec.iter()) {
- *oel = (*iel as i32) - 128;
- }
- remix_i32(&channel_op, &tvec1, &mut tvec2);
- for (oel, iel) in dvec.iter_mut().zip(tvec2.iter()) {
- *oel = (*iel + 128).min(255).max(0) as u8;
- }
- }
- store_samples(db, i, &dvec);
+ let sstep = src.get_audio_step().max(1);
+ let dstep = dst_buf.get_audio_step().max(1);
+ let sr: Box<dyn SampleReader> = match src {
+ NABufferType::AudioU8(ref ab) => {
+ let stride = ab.get_stride();
+ let data = ab.get_data();
+ if !src_fmt.signed {
+ Box::new(GenericSampleReader { data, stride })
+ } else {
+ Box::new(S8SampleReader { data, stride })
}
},
- (NABufferType::AudioI16(sb), NABufferType::AudioI16(ref mut db)) => {
- let mut svec = vec![0; src_chmap.num_channels()];
- let mut tvec1 = vec![0; src_chmap.num_channels()];
- let mut tvec2 = vec![0; dst_chmap.num_channels()];
- let mut dvec = vec![0; dst_chmap.num_channels()];
- for i in 0..nsamples {
- read_samples(sb, i, &mut svec);
- if !channel_op.is_remix() {
- apply_channel_op(&channel_op, &svec, &mut dvec);
- } else {
- for (oel, iel) in tvec1.iter_mut().zip(svec.iter()) {
- *oel = *iel as i32;
- }
- remix_i32(&channel_op, &tvec1, &mut tvec2);
- for (oel, iel) in dvec.iter_mut().zip(tvec2.iter()) {
- *oel = (*iel).min(16383).max(-16384) as i16;
- }
- }
- store_samples(db, i, &dvec);
- }
+ NABufferType::AudioI16(ref ab) => {
+ let data = ab.get_data();
+ let stride = ab.get_stride();
+ Box::new(GenericSampleReader { data, stride })
},
- (NABufferType::AudioI32(sb), NABufferType::AudioI32(ref mut db)) => {
- let mut svec = vec![0; src_chmap.num_channels()];
- let mut dvec = vec![0; dst_chmap.num_channels()];
- for i in 0..nsamples {
- read_samples(sb, i, &mut svec);
- if !channel_op.is_remix() {
- apply_channel_op(&channel_op, &svec, &mut dvec);
- } else {
- remix_i32(&channel_op, &svec, &mut dvec);
- }
- store_samples(db, i, &dvec);
- }
+ NABufferType::AudioI32(ref ab) => {
+ let data = ab.get_data();
+ let stride = ab.get_stride();
+ Box::new(GenericSampleReader { data, stride })
},
- (NABufferType::AudioF32(sb), NABufferType::AudioF32(ref mut db)) => {
- let mut svec = vec![0.0; src_chmap.num_channels()];
- let mut dvec = vec![0.0; dst_chmap.num_channels()];
- for i in 0..nsamples {
- read_samples(sb, i, &mut svec);
- if !channel_op.is_remix() {
- apply_channel_op(&channel_op, &svec, &mut dvec);
- } else {
- remix_f32(&channel_op, &svec, &mut dvec);
- }
- store_samples(db, i, &dvec);
- }
+ NABufferType::AudioF32(ref ab) => {
+ let data = ab.get_data();
+ let stride = ab.get_stride();
+ Box::new(GenericSampleReader { data, stride })
+ },
+ NABufferType::AudioPacked(ref ab) => {
+ let data = ab.get_data();
+ Box::new(PackedSampleReader::new(data, src_fmt))
},
_ => unimplemented!(),
};
- } else {
- let into_float = dst_fmt.float;
- if !into_float {
- let mut svec = vec![0i32; src_chmap.num_channels()];
- let mut dvec = vec![0i32; dst_chmap.num_channels()];
- for i in 0..nsamples {
- match src {
- NABufferType::AudioU8 (ref sb) => read_samples_i32(sb, i, &mut svec),
- NABufferType::AudioI16(ref sb) => read_samples_i32(sb, i, &mut svec),
- NABufferType::AudioI32(ref sb) => read_samples_i32(sb, i, &mut svec),
- NABufferType::AudioF32(ref sb) => read_samples_i32(sb, i, &mut svec),
- NABufferType::AudioPacked(ref sb) => read_packed(sb, i, &mut svec, &src_fmt),
- _ => unreachable!(),
- };
- if !channel_op.is_remix() {
- apply_channel_op(&channel_op, &svec, &mut dvec);
- } else {
- remix_i32(&channel_op, &svec, &mut dvec);
- }
- match dst_buf {
- NABufferType::AudioU8 (ref mut db) => store_samples(db, i, &dvec),
- NABufferType::AudioI16(ref mut db) => store_samples(db, i, &dvec),
- NABufferType::AudioI32(ref mut db) => store_samples(db, i, &dvec),
- NABufferType::AudioF32(ref mut db) => store_samples(db, i, &dvec),
- NABufferType::AudioPacked(ref mut buf) => store_packed(buf, i, &dvec, &dst_fmt),
- _ => unreachable!(),
- };
+ let mut sw: Box<dyn SampleWriter> = match dst_buf {
+ NABufferType::AudioU8(ref mut ab) => {
+ let stride = ab.get_stride();
+ let data = ab.get_data_mut().unwrap();
+ Box::new(GenericSampleWriter { data, stride })
+ },
+ NABufferType::AudioI16(ref mut ab) => {
+ let stride = ab.get_stride();
+ let data = ab.get_data_mut().unwrap();
+ Box::new(GenericSampleWriter { data, stride })
+ },
+ NABufferType::AudioI32(ref mut ab) => {
+ let stride = ab.get_stride();
+ let data = ab.get_data_mut().unwrap();
+ Box::new(GenericSampleWriter { data, stride })
+ },
+ NABufferType::AudioF32(ref mut ab) => {
+ let stride = ab.get_stride();
+ let data = ab.get_data_mut().unwrap();
+ Box::new(GenericSampleWriter { data, stride })
+ },
+ NABufferType::AudioPacked(ref mut ab) => {
+ let data = ab.get_data_mut().unwrap();
+ Box::new(PackedSampleWriter::new(data, dst_fmt))
+ },
+ _ => unimplemented!(),
+ };
+
+ let into_float = dst_fmt.float;
+ if !into_float {
+ let mut svec = vec![0; src_chmap.num_channels()];
+ let mut dvec = vec![0; dst_chmap.num_channels()];
+ let mut spos = 0;
+ let mut dpos = 0;
+ for _ in 0..nsamples {
+ sr.get_samples_i32(spos, &mut svec);
+ if !channel_op.is_remix() {
+ apply_channel_op(&channel_op, &svec, &mut dvec);
+ } else {
+ remix_i32(&channel_op, &svec, &mut dvec);
}
- } else {
- let mut svec = vec![0.0f32; src_chmap.num_channels()];
- let mut dvec = vec![0.0f32; dst_chmap.num_channels()];
- for i in 0..nsamples {
- match src {
- NABufferType::AudioU8 (ref sb) => read_samples_f32(sb, i, &mut svec),
- NABufferType::AudioI16(ref sb) => read_samples_f32(sb, i, &mut svec),
- NABufferType::AudioI32(ref sb) => read_samples_f32(sb, i, &mut svec),
- NABufferType::AudioF32(ref sb) => read_samples_f32(sb, i, &mut svec),
- NABufferType::AudioPacked(ref sb) => read_packed(sb, i, &mut svec, &src_fmt),
- _ => unreachable!(),
- };
- if !channel_op.is_remix() {
- apply_channel_op(&channel_op, &svec, &mut dvec);
- } else {
- remix_f32(&channel_op, &svec, &mut dvec);
- }
- match dst_buf {
- NABufferType::AudioU8 (ref mut db) => store_samples(db, i, &dvec),
- NABufferType::AudioI16(ref mut db) => store_samples(db, i, &dvec),
- NABufferType::AudioI32(ref mut db) => store_samples(db, i, &dvec),
- NABufferType::AudioF32(ref mut db) => store_samples(db, i, &dvec),
- NABufferType::AudioPacked(ref mut buf) => store_packed(buf, i, &dvec, &dst_fmt),
- _ => unreachable!(),
- };
+ sw.store_samples_i32(dpos, &dvec);
+ spos += sstep;
+ dpos += dstep;
+ }
+ } else {
+ let mut svec = vec![0.0; src_chmap.num_channels()];
+ let mut dvec = vec![0.0; dst_chmap.num_channels()];
+ let mut spos = 0;
+ let mut dpos = 0;
+ for _ in 0..nsamples {
+ sr.get_samples_f32(spos, &mut svec);
+ if !channel_op.is_remix() {
+ apply_channel_op(&channel_op, &svec, &mut dvec);
+ } else {
+ remix_f32(&channel_op, &svec, &mut dvec);
}
+ sw.store_samples_f32(dpos, &dvec);
+ spos += sstep;
+ dpos += dstep;
}
}
-
+ drop(sw);
+
Ok(dst_buf)
}
+/// Checks whether two channel maps are identical.
pub fn channel_maps_equal(a: &NAChannelMap, b: &NAChannelMap) -> bool {
if a.num_channels() != b.num_channels() { return false; }
for i in 0..a.num_channels() {
true
}
+/// Checks whether two channel maps have identical channels (but maybe in different order).
pub fn channel_maps_reordered(a: &NAChannelMap, b: &NAChannelMap) -> bool {
if a.num_channels() != b.num_channels() { return false; }
let mut count_a = [0u8; 32];
true
}
+/// Calculates permutation matrix for reordering channels from source channel map into destination one.
pub fn calculate_reorder_matrix(src: &NAChannelMap, dst: &NAChannelMap) -> Vec<usize> {
if src.num_channels() != dst.num_channels() { return Vec::new(); }
let num_channels = src.num_channels();
fn is_stereo(chmap: &NAChannelMap) -> bool {
(chmap.num_channels() == 2) &&
- (chmap.get_channel(0) == NAChannelType::L) &&
+ (chmap.get_channel(0) == NAChannelType::L) &&
(chmap.get_channel(1) == NAChannelType::R)
}
+/// Calculates matrix of remixing coefficients for converting input channel layout into destination one.
pub fn calculate_remix_matrix(src: &NAChannelMap, dst: &NAChannelMap) -> Vec<f32> {
if is_stereo(src) && dst.num_channels() == 1 &&
(dst.get_channel(0) == NAChannelType::L || dst.get_channel(0) == NAChannelType::C) {
block_len: 512,
};
let mut src_frm = alloc_audio_buffer(src_ainfo, 42, chcfg51.clone()).unwrap();
- if let NABufferType::AudioPacked(ref mut abuf) = src_frm {
+ if let NABufferType::AudioU8(ref mut abuf) = src_frm {
let data = abuf.get_data_mut().unwrap();
let mut idx = 0;
for _ in 0..42 {
let l = data[off0];
let r = data[off1];
assert_eq!(l, 7445);
- assert_eq!(r, -19943);
+ assert_eq!(r, -19505);
} else {
panic!("wrong buffer type");
}
} else {
panic!("wrong buffer type");
}
+
+ const PCM12: &[u8] = &[ 0x02, 0x50, 0x00, 0x07, 0x70, 0x00, 0x0D, 0x00 ];
+ const PCM12_SAMPLES: usize = 5;
+ let src_ainfo = NAAudioInfo {
+ sample_rate: 44100,
+ channels: 1,
+ format: NASoniton::new(12, SONITON_FLAG_PACKED | SONITON_FLAG_SIGNED),
+ block_len: 3,
+ };
+ let dst_ainfo = NAAudioInfo {
+ sample_rate: 44100,
+ channels: 1,
+ format: SND_S16P_FORMAT,
+ block_len: 512,
+ };
+ let mono = NAChannelMap::from_str("C").unwrap();
+ let mut src_frm = alloc_audio_buffer(src_ainfo, PCM12_SAMPLES, mono.clone()).unwrap();
+ if let NABufferType::AudioPacked(ref mut abuf) = src_frm {
+ let data = abuf.get_data_mut().unwrap();
+ data.copy_from_slice(PCM12);
+ } else {
+ panic!("wrong buffer type");
+ }
+ let out_frm = convert_audio_frame(&src_frm, &dst_ainfo, &mono).unwrap();
+ if let NABufferType::AudioI16(ref abuf) = out_frm {
+ let data = abuf.get_data();
+ assert_eq!(data.len(), PCM12_SAMPLES);
+ assert_eq!(data[0], 0x0020);
+ assert_eq!(data[1], 0x0050);
+ assert_eq!(data[2], 0x0070);
+ assert_eq!(data[3], 0x0070);
+ assert_eq!(data[4], 0x00D0);
+ } else {
+ panic!("wrong buffer type");
+ }
}
}