X-Git-Url: https://git.nihav.org/?a=blobdiff_plain;f=nihav-core%2Fsrc%2Fsoundcvt%2Fmod.rs;h=a9f16c623b5e8dd0f3fc888b0f2f65ecb1f33d5d;hb=6f2630992fe340ad1a122ec10c649f756e478185;hp=4f9d81c1189d2912bc9854aa4a2bb541d79439fd;hpb=886156da5a55514f145b5c4f2e9ff936b263e4cd;p=nihav.git diff --git a/nihav-core/src/soundcvt/mod.rs b/nihav-core/src/soundcvt/mod.rs index 4f9d81c..a9f16c6 100644 --- a/nihav-core/src/soundcvt/mod.rs +++ b/nihav-core/src/soundcvt/mod.rs @@ -29,18 +29,14 @@ 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: &Vec, 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.as_slice()); + dst.copy_from_slice(src); }, ChannelOp::Reorder(ref reorder) => { for (out, idx) in dst.iter_mut().zip(reorder.iter()) { @@ -51,7 +47,7 @@ fn apply_channel_op(ch_op: &ChannelOp, src: &Vec, dst: &mut Vec) { }; } -fn remix_i32(ch_op: &ChannelOp, src: &Vec, 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 +66,7 @@ fn remix_i32(ch_op: &ChannelOp, src: &Vec, dst: &mut Vec) { } } -fn remix_f32(ch_op: &ChannelOp, src: &Vec, 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)) { @@ -97,13 +93,13 @@ impl FromFmt for u8 { fn cvt_from(val: u8) -> u8 { val } } impl FromFmt for i16 { - fn cvt_from(val: u8) -> i16 { ((val as i16) - 128).wrapping_mul(0x101) } + fn cvt_from(val: u8) -> i16 { u16::from(val ^ 0x80).wrapping_mul(0x101) as i16} } impl FromFmt for i32 { - fn cvt_from(val: u8) -> i32 { ((val as i32) - 128).wrapping_mul(0x01010101) } + fn cvt_from(val: u8) -> i32 { u32::from(val ^ 0x80).wrapping_mul(0x01010101) as i32 } } impl FromFmt 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 for u8 { @@ -113,10 +109,10 @@ impl FromFmt for i16 { fn cvt_from(val: i16) -> i16 { val } } impl FromFmt for i32 { - fn cvt_from(val: i16) -> i32 { (val as i32).wrapping_mul(0x10001) } + fn cvt_from(val: i16) -> i32 { (i32::from(val) & 0xFFFF) | (i32::from(val) << 16) } } impl FromFmt 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 for u8 { @@ -136,10 +132,19 @@ impl FromFmt for u8 { fn cvt_from(val: f32) -> u8 { ((val * 128.0) + 128.0).min(255.0).max(0.0) as u8 } } impl FromFmt 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 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 +160,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 +170,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 +186,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, @@ -193,14 +220,14 @@ impl<'a> PackedSampleReader<'a> { 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 { 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,17 +251,17 @@ 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); } } trait SampleWriter { - fn store_samples_i32(&mut self, pos: usize, src: &Vec); - fn store_samples_f32(&mut self, pos: usize, src: &Vec); + 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> { @@ -243,14 +270,14 @@ struct GenericSampleWriter<'a, T:Copy> { } impl<'a, T:Copy+FromFmt+FromFmt> SampleWriter for GenericSampleWriter<'a, T> { - fn store_samples_i32(&mut self, pos: usize, src: &Vec) { + 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: &Vec) { + 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(); @@ -272,7 +299,7 @@ impl<'a> PackedSampleWriter<'a> { Self { data, fmt, bpp } } - fn store_samples(&mut self, pos: usize, src: &Vec) where u8: FromFmt, i16: FromFmt, i32: FromFmt, f32: FromFmt { + fn store_samples(&mut self, pos: usize, src: &[T]) where u8: FromFmt, i16: FromFmt, i32: FromFmt, f32: FromFmt { let mut offset = pos * self.bpp * src.len(); for el in src.iter() { let dst = &mut self.data[offset..]; @@ -280,6 +307,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(), @@ -293,8 +323,8 @@ impl<'a> PackedSampleWriter<'a> { 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, f32::cvt_from(*el) as f64).unwrap(), - (8, false) => write_f64le(dst, f32::cvt_from(*el) as f64).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!(), }; } @@ -304,10 +334,10 @@ impl<'a> PackedSampleWriter<'a> { } impl SampleWriter for PackedSampleWriter<'_> { - fn store_samples_i32(&mut self, pos: usize, src: &Vec) { + fn store_samples_i32(&mut self, pos: usize, src: &[i32]) { self.store_samples(pos, src); } - fn store_samples_f32(&mut self, pos: usize, src: &Vec) { + fn store_samples_f32(&mut self, pos: usize, src: &[f32]) { self.store_samples(pos, src); } } @@ -362,17 +392,23 @@ Result { 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(); + let sstep = src.get_audio_step().max(1); + let dstep = dst_buf.get_audio_step().max(1); let sr: Box = match src { 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(); @@ -427,26 +463,34 @@ Result { if !into_float { let mut svec = vec![0; src_chmap.num_channels()]; let mut dvec = vec![0; dst_chmap.num_channels()]; - for i in 0..nsamples { - sr.get_samples_i32(i, &mut svec); + 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); } - sw.store_samples_i32(i, &dvec); + 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()]; - for i in 0..nsamples { - sr.get_samples_f32(i, &mut svec); + 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(i, &dvec); + sw.store_samples_f32(dpos, &dvec); + spos += sstep; + dpos += dstep; } } drop(sw); @@ -566,7 +610,7 @@ mod test { 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 { @@ -587,7 +631,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"); }