X-Git-Url: https://git.nihav.org/?a=blobdiff_plain;f=nihav-core%2Fsrc%2Fsoundcvt%2Fmod.rs;h=bb307b91e581e3c21f51c83609cf55c9d0f68af3;hb=9fce24c89edfe18da71acf4a44ffca03b1575fe6;hp=f1079257b78da801d03d4b3fcf74f23d0640bb41;hpb=9a5f37d5d943cbf76313f7fd87b496f6de1f65a7;p=nihav.git diff --git a/nihav-core/src/soundcvt/mod.rs b/nihav-core/src/soundcvt/mod.rs index f107925..bb307b9 100644 --- a/nihav-core/src/soundcvt/mod.rs +++ b/nihav-core/src/soundcvt/mod.rs @@ -7,6 +7,7 @@ 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; /// A list specifying general sound conversion errors. @@ -29,15 +30,11 @@ enum ChannelOp { impl ChannelOp { fn is_remix(&self) -> bool { - match *self { - ChannelOp::Remix(_) => true, - ChannelOp::DupMono(_) => true, - _ => false, - } + matches! (*self, ChannelOp::Remix(_) | ChannelOp::DupMono(_)) } } -fn apply_channel_op(ch_op: &ChannelOp, src: &[T], dst: &mut Vec) { +fn apply_channel_op(ch_op: &ChannelOp, src: &[T], dst: &mut [T]) { match *ch_op { ChannelOp::Passthrough => { dst.copy_from_slice(src); @@ -51,7 +48,7 @@ fn apply_channel_op(ch_op: &ChannelOp, src: &[T], dst: &mut Vec) { }; } -fn remix_i32(ch_op: &ChannelOp, src: &[i32], dst: &mut Vec) { +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)) { @@ -70,7 +67,7 @@ fn remix_i32(ch_op: &ChannelOp, src: &[i32], dst: &mut Vec) { } } -fn remix_f32(ch_op: &ChannelOp, src: &[f32], dst: &mut Vec) { +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)) { @@ -139,7 +136,16 @@ impl FromFmt for i16 { fn cvt_from(val: f32) -> i16 { (val * 32768.0).min(32767.0).max(-32768.0) as i16 } } impl FromFmt 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 for f32 { fn cvt_from(val: f32) -> f32 { val } @@ -155,8 +161,8 @@ impl IntoFmt for T where U: FromFmt { trait SampleReader { - fn get_samples_i32(&self, pos: usize, dst: &mut Vec); - fn get_samples_f32(&self, pos: usize, dst: &mut Vec); + 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> { @@ -165,14 +171,14 @@ struct GenericSampleReader<'a, T:Copy> { } impl<'a, T:Copy+IntoFmt+IntoFmt> SampleReader for GenericSampleReader<'a, T> { - fn get_samples_i32(&self, pos: usize, dst: &mut Vec) { + 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 Vec) { + 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(); @@ -181,6 +187,28 @@ impl<'a, T:Copy+IntoFmt+IntoFmt> SampleReader for GenericSampleReader< } } +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; + } + } +} + struct PackedSampleReader<'a> { data: &'a [u8], fmt: NASoniton, @@ -189,18 +217,39 @@ struct PackedSampleReader<'a> { impl<'a> PackedSampleReader<'a> { fn new(data: &'a [u8], fmt: NASoniton) -> Self { - if (fmt.bits & 7) != 0 { unimplemented!(); } let bpp = (fmt.bits >> 3) as usize; Self { data, fmt, bpp } } - fn get_samples(&self, pos: usize, dst: &mut Vec) where u8: IntoFmt, i16: IntoFmt, i32: IntoFmt, f32: IntoFmt { + fn get_samples(&self, pos: usize, dst: &mut [T]) where u8: IntoFmt, i16: IntoFmt, i32: IntoFmt, f32: IntoFmt { + 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 { + for el in dst.iter_mut() { + *el = 0i16.cvt_into(); + } + } + + return; + } + 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, _) => src[0].cvt_into(), + (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(), @@ -224,10 +273,10 @@ impl<'a> PackedSampleReader<'a> { } impl SampleReader for PackedSampleReader<'_> { - fn get_samples_i32(&self, pos: usize, dst: &mut Vec) { + fn get_samples_i32(&self, pos: usize, dst: &mut [i32]) { self.get_samples(pos, dst); } - fn get_samples_f32(&self, pos: usize, dst: &mut Vec) { + fn get_samples_f32(&self, pos: usize, dst: &mut [f32]) { self.get_samples(pos, dst); } } @@ -280,6 +329,9 @@ impl<'a> PackedSampleWriter<'a> { 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(), @@ -315,7 +367,7 @@ impl SampleWriter for PackedSampleWriter<'_> { /// 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 { - let mut nsamples = src.get_audio_length(); + let nsamples = src.get_audio_length(); if nsamples == 0 { return Err(SoundConvertError::InvalidInput); } @@ -325,10 +377,6 @@ Result { return Err(SoundConvertError::InvalidInput); } - if let NABufferType::AudioPacked(_) = src { - nsamples = nsamples * 8 / (src_info.get_format().get_bits() as usize) / src_chmap.num_channels(); - } - let needs_remix = src_chmap.num_channels() != dst_chmap.num_channels(); let no_channel_needs = !needs_remix && channel_maps_equal(src_chmap, dst_chmap); let needs_reorder = !needs_remix && !no_channel_needs && channel_maps_reordered(src_chmap, dst_chmap); @@ -374,7 +422,11 @@ Result { NABufferType::AudioU8(ref ab) => { let stride = ab.get_stride(); let data = ab.get_data(); - Box::new(GenericSampleReader { data, stride }) + if !src_fmt.signed { + Box::new(GenericSampleReader { data, stride }) + } else { + Box::new(S8SampleReader { data, stride }) + } }, NABufferType::AudioI16(ref ab) => { let data = ab.get_data(); @@ -597,7 +649,7 @@ mod test { 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"); } @@ -615,5 +667,40 @@ mod test { } 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"); + } } }