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