1#[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
3#[must_use]
4pub fn resample_and_mix(
5 input: &[i16],
6 in_channels: usize,
7 in_rate: u32,
8 out_channels: usize,
9 out_rate: u32,
10) -> Vec<i16> {
11 if input.is_empty() {
12 return Vec::new();
13 }
14
15 let num_input_frames = input.len() / in_channels;
16 let ratio = out_rate as f32 / in_rate as f32;
17 let num_output_frames = (num_input_frames as f32 * ratio).ceil() as usize;
19
20 let mut output = Vec::with_capacity(num_output_frames * out_channels);
21
22 for i in 0..num_output_frames {
23 let src_idx_float = i as f32 / ratio;
24 let src_idx_floor = src_idx_float.floor() as usize;
25 let t = src_idx_float - src_idx_floor as f32;
26
27 let mut src_frame = vec![0.0; in_channels];
29
30 if src_idx_floor < num_input_frames {
31 let idx0 = src_idx_floor * in_channels;
32 let idx1 = if src_idx_floor + 1 < num_input_frames {
33 (src_idx_floor + 1) * in_channels
34 } else {
35 idx0 };
37
38 for c in 0..in_channels {
39 let s0 = f32::from(input[idx0 + c]);
40 let s1 = f32::from(input[idx1 + c]);
41 src_frame[c] = s0 + (s1 - s0) * t;
42 }
43 }
44
45 if in_channels == 1 && out_channels == 2 {
47 let val = src_frame[0] as i16;
49 output.push(val);
50 output.push(val);
51 } else if in_channels == 2 && out_channels == 1 {
52 let val = ((src_frame[0] + src_frame[1]) * 0.5) as i16;
54 output.push(val);
55 } else if in_channels == out_channels {
56 output.extend(src_frame.iter().map(|&s| s as i16));
58 } else {
59 for &s in src_frame.iter().take(out_channels) {
61 output.push(s as i16);
62 }
63 if out_channels > in_channels {
64 output.extend(std::iter::repeat_n(0, out_channels - in_channels));
65 }
66 }
67 }
68
69 output
70}