ljud/utils/
resample.rs

1use arrayvec::ArrayVec;
2
3pub fn linear_resample<const N: usize>(input: &[f32], output: &mut ArrayVec<f32, N>) {
4    let input_len = input.len();
5    let output_len = output.len();
6    let scale = (input_len - 1) as f32 / (output_len - 1) as f32;
7
8    for i in 0..output_len {
9        let pos = i as f32 * scale;
10        let pos_floor = pos.floor() as usize;
11        let pos_ceil = pos.ceil() as usize;
12
13        if pos_ceil >= input_len {
14            output[i] = input[input_len - 1];
15        } else if pos_floor == pos_ceil {
16            output[i] = input[pos_floor];
17        } else {
18            let weight = pos - pos_floor as f32;
19            output[i] = input[pos_floor] * (1.0 - weight) + input[pos_ceil] * weight;
20        }
21    }
22}
23
24// avoid generate new buffer
25// const BUFFER_SIZE: usize = 1024;
26
27// fn main() {
28//     let input_signal: &[f32] = &[1.0, 2.0, 3.0, 4.0, 5.0];
29//     let mut output_signal = ArrayVec::<_, BUFFER_SIZE>::new();
30//     output_signal.extend((0..10).map(|_| 0.0));
31
32//     linear_resample::<BUFFER_SIZE>(input_signal, &mut output_signal);
33
34//     println!("{:?}", output_signal);
35// }
36
37pub fn cubic_interpolation(y0: f32, y1: f32, y2: f32, y3: f32, t: f32) -> f32 {
38    let a0 = -0.5 * y0 + 1.5 * y1 - 1.5 * y2 + 0.5 * y3;
39    let a1 = y0 - 2.5 * y1 + 2.0 * y2 - 0.5 * y3;
40    let a2 = -0.5 * y0 + 0.5 * y2;
41    let a3 = y1;
42
43    a0 * t * t * t + a1 * t * t + a2 * t + a3
44}
45
46pub fn cubic_resample<const N: usize>(input: &[f32], output: &mut ArrayVec<f32, N>) {
47    let input_len = input.len();
48    let output_len = output.len();
49    let scale = (input_len - 1) as f32 / (output_len - 1) as f32;
50
51    for i in 0..output_len {
52        let pos = i as f32 * scale;
53        let pos_floor = pos.floor() as usize;
54
55        let y0 = if pos_floor == 0 {
56            input[pos_floor]
57        } else {
58            input[pos_floor - 1]
59        };
60        let y1 = input[pos_floor];
61        let y2 = if pos_floor + 1 < input_len {
62            input[pos_floor + 1]
63        } else {
64            input[input_len - 1]
65        };
66        let y3 = if pos_floor + 2 < input_len {
67            input[pos_floor + 2]
68        } else {
69            input[input_len - 1]
70        };
71
72        let t = pos - pos_floor as f32;
73        output[i] = cubic_interpolation(y0, y1, y2, y3, t);
74    }
75}
76
77// fn main() {
78//     let input_signal: &[f32] = &[1.0, 2.0, 3.0, 4.0, 5.0];
79//     let mut output_signal = ArrayVec::<f32, 1024>::new();
80//     output_signal.extend((0..10).map(|_| 0.0));
81
82//     cubic_resample::<1024>(input_signal, &mut output_signal);
83
84//     println!("{:?}", output_signal);
85// }