core/soundcvt: support conversion from packed audio
[nihav.git] / nihav-core / src / soundcvt / mod.rs
CommitLineData
886156da
KS
1//! Sound format conversion.
2//!
3//! 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.
4//! Eventually this might support resampling as well.
47f26235
KS
5pub use crate::formats::{NASoniton,NAChannelMap};
6pub use crate::frame::{NAAudioBuffer,NAAudioInfo,NABufferType};
7use crate::formats::NAChannelType;
8use crate::frame::alloc_audio_buffer;
9use crate::io::byteio::*;
9fce24c8 10use crate::io::bitreader::*;
47f26235
KS
11use std::f32::consts::SQRT_2;
12
886156da 13/// A list specifying general sound conversion errors.
47f26235
KS
14#[derive(Clone,Copy,Debug,PartialEq)]
15pub enum SoundConvertError {
886156da 16 /// Invalid input arguments.
47f26235 17 InvalidInput,
886156da 18 /// Allocation failed.
47f26235 19 AllocError,
886156da 20 /// Requested feature is not supported.
47f26235
KS
21 Unsupported,
22}
23
24enum ChannelOp {
25 Passthrough,
26 Reorder(Vec<usize>),
27 Remix(Vec<f32>),
582ffb7b 28 DupMono(Vec<bool>),
47f26235
KS
29}
30
31impl ChannelOp {
32 fn is_remix(&self) -> bool {
6f263099 33 matches! (*self, ChannelOp::Remix(_) | ChannelOp::DupMono(_))
47f26235
KS
34 }
35}
36
6f263099 37fn apply_channel_op<T:Copy>(ch_op: &ChannelOp, src: &[T], dst: &mut [T]) {
47f26235
KS
38 match *ch_op {
39 ChannelOp::Passthrough => {
b36f412c 40 dst.copy_from_slice(src);
47f26235
KS
41 },
42 ChannelOp::Reorder(ref reorder) => {
43 for (out, idx) in dst.iter_mut().zip(reorder.iter()) {
44 *out = src[*idx];
45 }
46 },
47 _ => {},
48 };
49}
50
6f263099 51fn remix_i32(ch_op: &ChannelOp, src: &[i32], dst: &mut [i32]) {
47f26235
KS
52 if let ChannelOp::Remix(ref remix_mat) = ch_op {
53 let sch = src.len();
54 for (out, coeffs) in dst.iter_mut().zip(remix_mat.chunks(sch)) {
55 let mut sum = 0.0;
56 for (inval, coef) in src.iter().zip(coeffs.iter()) {
57 sum += (*inval as f32) * *coef;
58 }
59 *out = sum as i32;
60 }
61 }
582ffb7b
KS
62 if let ChannelOp::DupMono(ref dup_mat) = ch_op {
63 let src = src[0];
64 for (out, copy) in dst.iter_mut().zip(dup_mat.iter()) {
65 *out = if *copy { src } else { 0 };
66 }
67 }
47f26235
KS
68}
69
6f263099 70fn remix_f32(ch_op: &ChannelOp, src: &[f32], dst: &mut [f32]) {
47f26235
KS
71 if let ChannelOp::Remix(ref remix_mat) = ch_op {
72 let sch = src.len();
73 for (out, coeffs) in dst.iter_mut().zip(remix_mat.chunks(sch)) {
74 let mut sum = 0.0;
75 for (inval, coef) in src.iter().zip(coeffs.iter()) {
76 sum += *inval * *coef;
77 }
78 *out = sum;
79 }
80 }
582ffb7b
KS
81 if let ChannelOp::DupMono(ref dup_mat) = ch_op {
82 let src = src[0];
83 for (out, copy) in dst.iter_mut().zip(dup_mat.iter()) {
84 *out = if *copy { src } else { 0.0 };
85 }
86 }
47f26235
KS
87}
88
47f26235
KS
89trait FromFmt<T:Copy> {
90 fn cvt_from(val: T) -> Self;
91}
92
93impl FromFmt<u8> for u8 {
94 fn cvt_from(val: u8) -> u8 { val }
95}
96impl FromFmt<u8> for i16 {
9a5f37d5 97 fn cvt_from(val: u8) -> i16 { u16::from(val ^ 0x80).wrapping_mul(0x101) as i16}
47f26235
KS
98}
99impl FromFmt<u8> for i32 {
9a5f37d5 100 fn cvt_from(val: u8) -> i32 { u32::from(val ^ 0x80).wrapping_mul(0x01010101) as i32 }
47f26235
KS
101}
102impl FromFmt<u8> for f32 {
b36f412c 103 fn cvt_from(val: u8) -> f32 { (f32::from(val) - 128.0) / 128.0 }
47f26235
KS
104}
105
106impl FromFmt<i16> for u8 {
107 fn cvt_from(val: i16) -> u8 { ((val >> 8) + 128).min(255).max(0) as u8 }
108}
109impl FromFmt<i16> for i16 {
110 fn cvt_from(val: i16) -> i16 { val }
111}
112impl FromFmt<i16> for i32 {
9a5f37d5 113 fn cvt_from(val: i16) -> i32 { (i32::from(val) & 0xFFFF) | (i32::from(val) << 16) }
47f26235
KS
114}
115impl FromFmt<i16> for f32 {
b36f412c 116 fn cvt_from(val: i16) -> f32 { f32::from(val) / 32768.0 }
47f26235
KS
117}
118
119impl FromFmt<i32> for u8 {
120 fn cvt_from(val: i32) -> u8 { ((val >> 24) + 128).min(255).max(0) as u8 }
121}
122impl FromFmt<i32> for i16 {
123 fn cvt_from(val: i32) -> i16 { (val >> 16) as i16 }
124}
125impl FromFmt<i32> for i32 {
126 fn cvt_from(val: i32) -> i32 { val }
127}
128impl FromFmt<i32> for f32 {
129 fn cvt_from(val: i32) -> f32 { (val as f32) / 31.0f32.exp2() }
130}
131
132impl FromFmt<f32> for u8 {
133 fn cvt_from(val: f32) -> u8 { ((val * 128.0) + 128.0).min(255.0).max(0.0) as u8 }
134}
135impl FromFmt<f32> for i16 {
9a5f37d5 136 fn cvt_from(val: f32) -> i16 { (val * 32768.0).min(32767.0).max(-32768.0) as i16 }
47f26235
KS
137}
138impl FromFmt<f32> for i32 {
c151de26
KS
139 fn cvt_from(val: f32) -> i32 {
140 if val >= 1.0 {
141 std::i32::MAX
142 } else if val <= -1.0 {
143 std::i32::MIN
144 } else {
145 let scale = (1u32 << 31) as f32;
146 (val * scale) as i32
147 }
148 }
47f26235
KS
149}
150impl FromFmt<f32> for f32 {
151 fn cvt_from(val: f32) -> f32 { val }
152}
153
154trait IntoFmt<T:Copy> {
155 fn cvt_into(self) -> T;
156}
157
158impl<T:Copy, U:Copy> IntoFmt<U> for T where U: FromFmt<T> {
159 fn cvt_into(self) -> U { U::cvt_from(self) }
160}
161
162
8809c626 163trait SampleReader {
6f263099
KS
164 fn get_samples_i32(&self, pos: usize, dst: &mut [i32]);
165 fn get_samples_f32(&self, pos: usize, dst: &mut [f32]);
8809c626
KS
166}
167
168struct GenericSampleReader<'a, T:Copy> {
169 data: &'a [T],
170 stride: usize,
171}
172
173impl<'a, T:Copy+IntoFmt<i32>+IntoFmt<f32>> SampleReader for GenericSampleReader<'a, T> {
6f263099 174 fn get_samples_i32(&self, pos: usize, dst: &mut [i32]) {
8809c626
KS
175 let mut off = pos;
176 for el in dst.iter_mut() {
177 *el = self.data[off].cvt_into();
178 off += self.stride;
179 }
180 }
6f263099 181 fn get_samples_f32(&self, pos: usize, dst: &mut [f32]) {
8809c626
KS
182 let mut off = pos;
183 for el in dst.iter_mut() {
184 *el = self.data[off].cvt_into();
185 off += self.stride;
186 }
47f26235
KS
187 }
188}
189
b3ed5db7
KS
190struct S8SampleReader<'a> {
191 data: &'a [u8],
192 stride: usize,
193}
194
195impl<'a> SampleReader for S8SampleReader<'a> {
6f263099 196 fn get_samples_i32(&self, pos: usize, dst: &mut [i32]) {
b3ed5db7
KS
197 let mut off = pos;
198 for el in dst.iter_mut() {
199 *el = (self.data[off] ^ 0x80).cvt_into();
200 off += self.stride;
201 }
202 }
6f263099 203 fn get_samples_f32(&self, pos: usize, dst: &mut [f32]) {
b3ed5db7
KS
204 let mut off = pos;
205 for el in dst.iter_mut() {
206 *el = (self.data[off] ^ 0x80).cvt_into();
207 off += self.stride;
208 }
209 }
210}
211
8809c626
KS
212struct PackedSampleReader<'a> {
213 data: &'a [u8],
214 fmt: NASoniton,
215 bpp: usize,
216}
217
218impl<'a> PackedSampleReader<'a> {
219 fn new(data: &'a [u8], fmt: NASoniton) -> Self {
8809c626
KS
220 let bpp = (fmt.bits >> 3) as usize;
221 Self { data, fmt, bpp }
222 }
6f263099 223 fn get_samples<T:Copy>(&self, pos: usize, dst: &mut [T]) where u8: IntoFmt<T>, i16: IntoFmt<T>, i32: IntoFmt<T>, f32: IntoFmt<T> {
9fce24c8
KS
224 if (self.fmt.bits & 7) != 0 {
225 let mode = if self.fmt.be { BitReaderMode::BE } else { BitReaderMode::LE };
226 let mut br = BitReader::new(self.data, mode);
227 let offset = pos * (self.fmt.bits as usize) * dst.len();
228
229 if br.skip(offset as u32).is_ok() {
230 for el in dst.iter_mut() {
231 if self.fmt.bits < 16 {
232 *el = ((br.read(self.fmt.bits).unwrap_or(0) as i16) << (16 - self.fmt.bits)).cvt_into();
233 } else {
234 *el = ((br.read(self.fmt.bits).unwrap_or(0) as i32) << (32 - self.fmt.bits)).cvt_into();
235 }
236 }
237 } else {
238 for el in dst.iter_mut() {
239 *el = 0i16.cvt_into();
240 }
241 }
242
243 return;
244 }
245
8809c626
KS
246 let mut offset = pos * self.bpp * dst.len();
247
248 for el in dst.iter_mut() {
249 let src = &self.data[offset..];
250 *el = if !self.fmt.float {
251 match (self.bpp, self.fmt.be) {
b3ed5db7 252 (1, _) => if !self.fmt.signed { src[0].cvt_into() } else { (src[0] ^ 0x80).cvt_into() },
8809c626
KS
253 (2, true) => (read_u16be(src).unwrap() as i16).cvt_into(),
254 (2, false) => (read_u16le(src).unwrap() as i16).cvt_into(),
255 (3, true) => ((read_u24be(src).unwrap() << 8) as i32).cvt_into(),
256 (3, false) => ((read_u24be(src).unwrap() << 8) as i32).cvt_into(),
257 (4, true) => (read_u32be(src).unwrap() as i32).cvt_into(),
258 (4, false) => (read_u32be(src).unwrap() as i32).cvt_into(),
259 _ => unreachable!(),
260 }
261 } else {
262 match (self.bpp, self.fmt.be) {
263 (4, true) => read_f32be(src).unwrap().cvt_into(),
264 (4, false) => read_f32le(src).unwrap().cvt_into(),
265 (8, true) => (read_f64be(src).unwrap() as f32).cvt_into(),
266 (8, false) => (read_f64le(src).unwrap() as f32).cvt_into(),
267 (_, _) => unreachable!(),
268 }
269 };
270 offset += self.bpp;
271 }
47f26235
KS
272 }
273}
274
8809c626 275impl SampleReader for PackedSampleReader<'_> {
6f263099 276 fn get_samples_i32(&self, pos: usize, dst: &mut [i32]) {
8809c626 277 self.get_samples(pos, dst);
47f26235 278 }
6f263099 279 fn get_samples_f32(&self, pos: usize, dst: &mut [f32]) {
8809c626
KS
280 self.get_samples(pos, dst);
281 }
282}
283
284trait SampleWriter {
b36f412c
KS
285 fn store_samples_i32(&mut self, pos: usize, src: &[i32]);
286 fn store_samples_f32(&mut self, pos: usize, src: &[f32]);
47f26235
KS
287}
288
8809c626
KS
289struct GenericSampleWriter<'a, T:Copy> {
290 data: &'a mut [T],
291 stride: usize,
292}
293
294impl<'a, T:Copy+FromFmt<i32>+FromFmt<f32>> SampleWriter for GenericSampleWriter<'a, T> {
b36f412c 295 fn store_samples_i32(&mut self, pos: usize, src: &[i32]) {
8809c626
KS
296 let mut off = pos;
297 for el in src.iter() {
298 self.data[off] = (*el).cvt_into();
299 off += self.stride;
300 }
301 }
b36f412c 302 fn store_samples_f32(&mut self, pos: usize, src: &[f32]) {
8809c626
KS
303 let mut off = pos;
304 for el in src.iter() {
305 self.data[off] = (*el).cvt_into();
306 off += self.stride;
307 }
47f26235
KS
308 }
309}
310
8809c626
KS
311struct PackedSampleWriter<'a> {
312 data: &'a mut [u8],
313 fmt: NASoniton,
314 bpp: usize,
315}
316
317impl<'a> PackedSampleWriter<'a> {
318 fn new(data: &'a mut [u8], fmt: NASoniton) -> Self {
319 if (fmt.bits & 7) != 0 { unimplemented!(); }
320 let bpp = (fmt.bits >> 3) as usize;
321 Self { data, fmt, bpp }
322 }
323
b36f412c 324 fn store_samples<T:Copy>(&mut self, pos: usize, src: &[T]) where u8: FromFmt<T>, i16: FromFmt<T>, i32: FromFmt<T>, f32: FromFmt<T> {
8809c626
KS
325 let mut offset = pos * self.bpp * src.len();
326 for el in src.iter() {
327 let dst = &mut self.data[offset..];
328 if !self.fmt.float {
329 match (self.bpp, self.fmt.be) {
330 (1, _) => {
331 dst[0] = u8::cvt_from(*el);
b3ed5db7
KS
332 if self.fmt.signed {
333 dst[0] ^= 0x80;
334 }
8809c626
KS
335 },
336 (2, true) => write_u16be(dst, i16::cvt_from(*el) as u16).unwrap(),
337 (2, false) => write_u16le(dst, i16::cvt_from(*el) as u16).unwrap(),
338 (3, true) => write_u24be(dst, (i32::cvt_from(*el) >> 8) as u32).unwrap(),
339 (3, false) => write_u24le(dst, (i32::cvt_from(*el) >> 8) as u32).unwrap(),
340 (4, true) => write_u32be(dst, i32::cvt_from(*el) as u32).unwrap(),
341 (4, false) => write_u32le(dst, i32::cvt_from(*el) as u32).unwrap(),
342 _ => unreachable!(),
343 };
344 } else {
345 match (self.bpp, self.fmt.be) {
346 (4, true) => write_f32be(dst, f32::cvt_from(*el)).unwrap(),
347 (4, false) => write_f32le(dst, f32::cvt_from(*el)).unwrap(),
b36f412c
KS
348 (8, true) => write_f64be(dst, f64::from(f32::cvt_from(*el))).unwrap(),
349 (8, false) => write_f64le(dst, f64::from(f32::cvt_from(*el))).unwrap(),
8809c626
KS
350 (_, _) => unreachable!(),
351 };
352 }
353 offset += self.bpp;
47f26235 354 }
8809c626
KS
355 }
356}
357
358impl SampleWriter for PackedSampleWriter<'_> {
b36f412c 359 fn store_samples_i32(&mut self, pos: usize, src: &[i32]) {
8809c626
KS
360 self.store_samples(pos, src);
361 }
b36f412c 362 fn store_samples_f32(&mut self, pos: usize, src: &[f32]) {
8809c626 363 self.store_samples(pos, src);
47f26235
KS
364 }
365}
366
886156da 367/// Converts input audio buffer into desired format and returns a newly allocated buffer.
d24468d9 368pub fn convert_audio_frame(src: &NABufferType, dst_info: &NAAudioInfo, dst_chmap: &NAChannelMap) ->
47f26235 369Result<NABufferType, SoundConvertError> {
9fce24c8 370 let nsamples = src.get_audio_length();
47f26235
KS
371 if nsamples == 0 {
372 return Err(SoundConvertError::InvalidInput);
373 }
374 let src_chmap = src.get_chmap().unwrap();
375 let src_info = src.get_audio_info().unwrap();
376 if (src_chmap.num_channels() == 0) || (dst_chmap.num_channels() == 0) {
377 return Err(SoundConvertError::InvalidInput);
378 }
379
380 let needs_remix = src_chmap.num_channels() != dst_chmap.num_channels();
381 let no_channel_needs = !needs_remix && channel_maps_equal(src_chmap, dst_chmap);
382 let needs_reorder = !needs_remix && !no_channel_needs && channel_maps_reordered(src_chmap, dst_chmap);
383
384 let channel_op = if no_channel_needs {
385 ChannelOp::Passthrough
386 } else if needs_reorder {
387 let reorder_mat = calculate_reorder_matrix(src_chmap, dst_chmap);
388 ChannelOp::Reorder(reorder_mat)
582ffb7b 389 } else if src_chmap.num_channels() > 1 {
47f26235
KS
390 let remix_mat = calculate_remix_matrix(src_chmap, dst_chmap);
391 ChannelOp::Remix(remix_mat)
582ffb7b
KS
392 } else {
393 let mut dup_mat: Vec<bool> = Vec::with_capacity(dst_chmap.num_channels());
394 for i in 0..dst_chmap.num_channels() {
395 let ch = dst_chmap.get_channel(i);
396 if ch.is_left() || ch.is_right() || ch == NAChannelType::C {
397 dup_mat.push(true);
398 } else {
399 dup_mat.push(false);
400 }
401 }
402 ChannelOp::DupMono(dup_mat)
47f26235
KS
403 };
404
405 let src_fmt = src_info.get_format();
406 let dst_fmt = dst_info.get_format();
407 let no_conversion = src_fmt == dst_fmt;
408
409 if no_conversion && no_channel_needs {
410 return Ok(src.clone());
411 }
412
b36f412c 413 let ret = alloc_audio_buffer(*dst_info, nsamples, dst_chmap.clone());
47f26235
KS
414 if ret.is_err() {
415 return Err(SoundConvertError::AllocError);
416 }
417 let mut dst_buf = ret.unwrap();
418
b9f94e7b
KS
419 let sstep = src.get_audio_step().max(1);
420 let dstep = dst_buf.get_audio_step().max(1);
8809c626
KS
421 let sr: Box<dyn SampleReader> = match src {
422 NABufferType::AudioU8(ref ab) => {
423 let stride = ab.get_stride();
424 let data = ab.get_data();
b3ed5db7
KS
425 if !src_fmt.signed {
426 Box::new(GenericSampleReader { data, stride })
427 } else {
428 Box::new(S8SampleReader { data, stride })
429 }
47f26235 430 },
8809c626
KS
431 NABufferType::AudioI16(ref ab) => {
432 let data = ab.get_data();
433 let stride = ab.get_stride();
434 Box::new(GenericSampleReader { data, stride })
47f26235 435 },
8809c626
KS
436 NABufferType::AudioI32(ref ab) => {
437 let data = ab.get_data();
438 let stride = ab.get_stride();
439 Box::new(GenericSampleReader { data, stride })
47f26235 440 },
8809c626
KS
441 NABufferType::AudioF32(ref ab) => {
442 let data = ab.get_data();
443 let stride = ab.get_stride();
444 Box::new(GenericSampleReader { data, stride })
445 },
446 NABufferType::AudioPacked(ref ab) => {
447 let data = ab.get_data();
448 Box::new(PackedSampleReader::new(data, src_fmt))
47f26235
KS
449 },
450 _ => unimplemented!(),
451 };
8809c626
KS
452 let mut sw: Box<dyn SampleWriter> = match dst_buf {
453 NABufferType::AudioU8(ref mut ab) => {
454 let stride = ab.get_stride();
455 let data = ab.get_data_mut().unwrap();
456 Box::new(GenericSampleWriter { data, stride })
457 },
458 NABufferType::AudioI16(ref mut ab) => {
459 let stride = ab.get_stride();
460 let data = ab.get_data_mut().unwrap();
461 Box::new(GenericSampleWriter { data, stride })
462 },
463 NABufferType::AudioI32(ref mut ab) => {
464 let stride = ab.get_stride();
465 let data = ab.get_data_mut().unwrap();
466 Box::new(GenericSampleWriter { data, stride })
467 },
468 NABufferType::AudioF32(ref mut ab) => {
469 let stride = ab.get_stride();
470 let data = ab.get_data_mut().unwrap();
471 Box::new(GenericSampleWriter { data, stride })
472 },
473 NABufferType::AudioPacked(ref mut ab) => {
474 let data = ab.get_data_mut().unwrap();
475 Box::new(PackedSampleWriter::new(data, dst_fmt))
476 },
477 _ => unimplemented!(),
478 };
479
480 let into_float = dst_fmt.float;
481 if !into_float {
482 let mut svec = vec![0; src_chmap.num_channels()];
483 let mut dvec = vec![0; dst_chmap.num_channels()];
98c6f2f0
KS
484 let mut spos = 0;
485 let mut dpos = 0;
486 for _ in 0..nsamples {
487 sr.get_samples_i32(spos, &mut svec);
8809c626
KS
488 if !channel_op.is_remix() {
489 apply_channel_op(&channel_op, &svec, &mut dvec);
490 } else {
491 remix_i32(&channel_op, &svec, &mut dvec);
47f26235 492 }
98c6f2f0
KS
493 sw.store_samples_i32(dpos, &dvec);
494 spos += sstep;
495 dpos += dstep;
8809c626
KS
496 }
497 } else {
498 let mut svec = vec![0.0; src_chmap.num_channels()];
499 let mut dvec = vec![0.0; dst_chmap.num_channels()];
98c6f2f0
KS
500 let mut spos = 0;
501 let mut dpos = 0;
502 for _ in 0..nsamples {
503 sr.get_samples_f32(spos, &mut svec);
8809c626
KS
504 if !channel_op.is_remix() {
505 apply_channel_op(&channel_op, &svec, &mut dvec);
506 } else {
507 remix_f32(&channel_op, &svec, &mut dvec);
47f26235 508 }
98c6f2f0
KS
509 sw.store_samples_f32(dpos, &dvec);
510 spos += sstep;
511 dpos += dstep;
47f26235
KS
512 }
513 }
8809c626 514 drop(sw);
d24468d9 515
47f26235
KS
516 Ok(dst_buf)
517}
518
886156da 519/// Checks whether two channel maps are identical.
47f26235
KS
520pub fn channel_maps_equal(a: &NAChannelMap, b: &NAChannelMap) -> bool {
521 if a.num_channels() != b.num_channels() { return false; }
522 for i in 0..a.num_channels() {
523 if a.get_channel(i) != b.get_channel(i) {
524 return false;
525 }
526 }
527 true
528}
529
886156da 530/// Checks whether two channel maps have identical channels (but maybe in different order).
47f26235
KS
531pub fn channel_maps_reordered(a: &NAChannelMap, b: &NAChannelMap) -> bool {
532 if a.num_channels() != b.num_channels() { return false; }
533 let mut count_a = [0u8; 32];
534 let mut count_b = [0u8; 32];
535 for i in 0..a.num_channels() {
536 count_a[a.get_channel(i) as usize] += 1;
537 count_b[b.get_channel(i) as usize] += 1;
538 }
539 for (c0, c1) in count_a.iter().zip(count_b.iter()) {
540 if *c0 != *c1 {
541 return false;
542 }
543 }
544 true
545}
546
886156da 547/// Calculates permutation matrix for reordering channels from source channel map into destination one.
47f26235
KS
548pub fn calculate_reorder_matrix(src: &NAChannelMap, dst: &NAChannelMap) -> Vec<usize> {
549 if src.num_channels() != dst.num_channels() { return Vec::new(); }
550 let num_channels = src.num_channels();
551 let mut reorder: Vec<usize> = Vec::with_capacity(num_channels);
552 for i in 0..num_channels {
553 let dst_ch = dst.get_channel(i);
554 for j in 0..num_channels {
555 if src.get_channel(j) == dst_ch {
556 reorder.push(j);
557 break;
558 }
559 }
560 }
561 if reorder.len() != num_channels { reorder.clear(); }
562 reorder
563}
564
565fn is_stereo(chmap: &NAChannelMap) -> bool {
566 (chmap.num_channels() == 2) &&
d24468d9 567 (chmap.get_channel(0) == NAChannelType::L) &&
47f26235
KS
568 (chmap.get_channel(1) == NAChannelType::R)
569}
570
886156da 571/// Calculates matrix of remixing coefficients for converting input channel layout into destination one.
47f26235
KS
572pub fn calculate_remix_matrix(src: &NAChannelMap, dst: &NAChannelMap) -> Vec<f32> {
573 if is_stereo(src) && dst.num_channels() == 1 &&
574 (dst.get_channel(0) == NAChannelType::L || dst.get_channel(0) == NAChannelType::C) {
575 return vec![0.5, 0.5];
576 }
577 if src.num_channels() >= 5 && is_stereo(dst) {
578 let src_nch = src.num_channels();
579 let mut mat = vec![0.0f32; src_nch * 2];
580 let (l_mat, r_mat) = mat.split_at_mut(src_nch);
581 for ch in 0..src_nch {
582 match src.get_channel(ch) {
583 NAChannelType::L => l_mat[ch] = 1.0,
584 NAChannelType::R => r_mat[ch] = 1.0,
585 NAChannelType::C => { l_mat[ch] = SQRT_2 / 2.0; r_mat[ch] = SQRT_2 / 2.0; },
586 NAChannelType::Ls => l_mat[ch] = SQRT_2 / 2.0,
587 NAChannelType::Rs => r_mat[ch] = SQRT_2 / 2.0,
588 _ => {},
589 };
590 }
591 return mat;
592 }
593unimplemented!();
594}
595
596#[cfg(test)]
597mod test {
598 use super::*;
599 use std::str::FromStr;
600 use crate::formats::*;
601
602 #[test]
603 fn test_matrices() {
604 let chcfg51 = NAChannelMap::from_str("L,R,C,LFE,Ls,Rs").unwrap();
605 let chcfg52 = NAChannelMap::from_str("C,L,R,Ls,Rs,LFE").unwrap();
606 let stereo = NAChannelMap::from_str("L,R").unwrap();
607 let reorder = calculate_reorder_matrix(&chcfg51, &chcfg52);
608 assert_eq!(reorder.as_slice(), [ 2, 0, 1, 4, 5, 3]);
609 let remix = calculate_remix_matrix(&chcfg51, &stereo);
610 assert_eq!(remix.as_slice(), [ 1.0, 0.0, SQRT_2 / 2.0, 0.0, SQRT_2 / 2.0, 0.0,
611 0.0, 1.0, SQRT_2 / 2.0, 0.0, 0.0, SQRT_2 / 2.0 ]);
612 }
613 #[test]
614 fn test_conversion() {
615 const CHANNEL_VALUES: [u8; 6] = [ 140, 90, 130, 128, 150, 70 ];
616 let chcfg51 = NAChannelMap::from_str("L,R,C,LFE,Ls,Rs").unwrap();
617 let stereo = NAChannelMap::from_str("L,R").unwrap();
618 let src_ainfo = NAAudioInfo {
619 sample_rate: 44100,
620 channels: chcfg51.num_channels() as u8,
621 format: SND_U8_FORMAT,
622 block_len: 512,
623 };
624 let mut dst_ainfo = NAAudioInfo {
625 sample_rate: 44100,
626 channels: stereo.num_channels() as u8,
627 format: SND_S16P_FORMAT,
628 block_len: 512,
629 };
630 let mut src_frm = alloc_audio_buffer(src_ainfo, 42, chcfg51.clone()).unwrap();
152e8f78 631 if let NABufferType::AudioU8(ref mut abuf) = src_frm {
47f26235
KS
632 let data = abuf.get_data_mut().unwrap();
633 let mut idx = 0;
634 for _ in 0..42 {
635 for ch in 0..chcfg51.num_channels() {
636 data[idx] = CHANNEL_VALUES[ch];
637 idx += 1;
638 }
639 }
640 } else {
641 panic!("wrong buffer type");
642 }
643
644 let out_frm = convert_audio_frame(&src_frm, &dst_ainfo, &stereo).unwrap();
645 if let NABufferType::AudioI16(ref abuf) = out_frm {
646 let off0 = abuf.get_offset(0);
647 let off1 = abuf.get_offset(1);
648 let data = abuf.get_data();
649 let l = data[off0];
650 let r = data[off1];
651 assert_eq!(l, 7445);
952dad98 652 assert_eq!(r, -19505);
47f26235
KS
653 } else {
654 panic!("wrong buffer type");
655 }
656
657 dst_ainfo.format = SND_F32P_FORMAT;
658 let out_frm = convert_audio_frame(&src_frm, &dst_ainfo, &stereo).unwrap();
659 if let NABufferType::AudioF32(ref abuf) = out_frm {
660 let off0 = abuf.get_offset(0);
661 let off1 = abuf.get_offset(1);
662 let data = abuf.get_data();
663 let l = data[off0];
664 let r = data[off1];
665 assert_eq!(l, 0.22633252);
666 assert_eq!(r, -0.6062342);
667 } else {
668 panic!("wrong buffer type");
669 }
9fce24c8
KS
670
671 const PCM12: &[u8] = &[ 0x02, 0x50, 0x00, 0x07, 0x70, 0x00, 0x0D, 0x00 ];
672 const PCM12_SAMPLES: usize = 5;
673 let src_ainfo = NAAudioInfo {
674 sample_rate: 44100,
675 channels: 1,
676 format: NASoniton::new(12, SONITON_FLAG_PACKED | SONITON_FLAG_SIGNED),
677 block_len: 3,
678 };
679 let dst_ainfo = NAAudioInfo {
680 sample_rate: 44100,
681 channels: 1,
682 format: SND_S16P_FORMAT,
683 block_len: 512,
684 };
685 let mono = NAChannelMap::from_str("C").unwrap();
686 let mut src_frm = alloc_audio_buffer(src_ainfo, PCM12_SAMPLES, mono.clone()).unwrap();
687 if let NABufferType::AudioPacked(ref mut abuf) = src_frm {
688 let data = abuf.get_data_mut().unwrap();
689 data.copy_from_slice(PCM12);
690 } else {
691 panic!("wrong buffer type");
692 }
693 let out_frm = convert_audio_frame(&src_frm, &dst_ainfo, &mono).unwrap();
694 if let NABufferType::AudioI16(ref abuf) = out_frm {
695 let data = abuf.get_data();
696 assert_eq!(data.len(), PCM12_SAMPLES);
697 assert_eq!(data[0], 0x0020);
698 assert_eq!(data[1], 0x0050);
699 assert_eq!(data[2], 0x0070);
700 assert_eq!(data[3], 0x0070);
701 assert_eq!(data[4], 0x00D0);
702 } else {
703 panic!("wrong buffer type");
704 }
47f26235
KS
705 }
706}