1pub fn resample_linear(input: &[f32], from_rate: u32, to_rate: u32) -> Vec<f32> {
16 if from_rate == to_rate || input.is_empty() {
17 return input.to_vec();
18 }
19
20 let ratio = from_rate as f64 / to_rate as f64;
21 let output_len = ((input.len() as f64) / ratio).ceil() as usize;
22 let mut output = Vec::with_capacity(output_len);
23
24 for i in 0..output_len {
25 let src_idx_f = i as f64 * ratio;
26 let src_idx = src_idx_f as usize;
27 let frac = src_idx_f - src_idx as f64;
28
29 let s0 = input.get(src_idx).copied().unwrap_or(0.0) as f64;
30 let s1 = input
31 .get(src_idx + 1)
32 .copied()
33 .unwrap_or_else(|| input.get(src_idx).copied().unwrap_or(0.0)) as f64;
34
35 let sample = s0 + frac * (s1 - s0);
36 output.push(sample as f32);
37 }
38
39 output
40}
41
42pub fn resample_linear_i16(input: &[i16], from_rate: u32, to_rate: u32) -> Vec<i16> {
44 if from_rate == to_rate || input.is_empty() {
45 return input.to_vec();
46 }
47
48 let ratio = from_rate as f64 / to_rate as f64;
49 let output_len = ((input.len() as f64) / ratio).ceil() as usize;
50 let mut output = Vec::with_capacity(output_len);
51
52 for i in 0..output_len {
53 let src_idx_f = i as f64 * ratio;
54 let src_idx = src_idx_f as usize;
55 let frac = src_idx_f - src_idx as f64;
56
57 let s0 = input.get(src_idx).copied().unwrap_or(0) as f64;
58 let s1 = input
59 .get(src_idx + 1)
60 .copied()
61 .unwrap_or_else(|| input.get(src_idx).copied().unwrap_or(0)) as f64;
62
63 let sample = s0 + frac * (s1 - s0);
64 output.push(sample.round() as i16);
65 }
66
67 output
68}
69
70pub fn f32_to_i16(input: &[f32]) -> Vec<i16> {
72 input.iter().map(|&s| (s * 32767.0) as i16).collect()
73}
74
75pub fn i16_to_f32(input: &[i16]) -> Vec<f32> {
77 input.iter().map(|&s| s as f32 / 32768.0).collect()
78}
79
80#[cfg(test)]
81mod tests {
82 use super::*;
83
84 #[test]
85 fn test_resample_upsample() {
86 let input: Vec<f32> = vec![0.0, 0.5, 1.0, 0.5, 0.0];
88 let output = resample_linear(&input, 8000, 48000);
89
90 assert!(output.len() >= 25);
92 assert!(output.len() <= 35);
93 }
94
95 #[test]
96 fn test_resample_downsample() {
97 let input: Vec<f32> = (0..960).map(|i| (i as f32 / 960.0) * 2.0 - 1.0).collect();
99 let output = resample_linear(&input, 48000, 8000);
100
101 assert!(output.len() >= 150);
103 assert!(output.len() <= 180);
104 }
105
106 #[test]
107 fn test_resample_same_rate() {
108 let input: Vec<f32> = vec![0.1, 0.2, 0.3, 0.4, 0.5];
109 let output = resample_linear(&input, 8000, 8000);
110
111 assert_eq!(input, output);
112 }
113
114 #[test]
115 fn test_resample_empty() {
116 let input: Vec<f32> = vec![];
117 let output = resample_linear(&input, 8000, 48000);
118
119 assert!(output.is_empty());
120 }
121
122 #[test]
123 fn test_f32_i16_conversion() {
124 let f32_samples = vec![0.0, 0.5, -0.5, 1.0, -1.0];
125 let i16_samples = f32_to_i16(&f32_samples);
126
127 assert_eq!(i16_samples[0], 0);
128 assert!((i16_samples[1] - 16383).abs() < 2);
129 assert!((i16_samples[2] + 16383).abs() < 2);
130
131 let back = i16_to_f32(&i16_samples);
132 for (a, b) in f32_samples.iter().zip(back.iter()) {
133 assert!((a - b).abs() < 0.001);
134 }
135 }
136
137 #[test]
138 fn test_resample_i16() {
139 let input: Vec<i16> = vec![0, 16384, 32767, 16384, 0];
140 let output = resample_linear_i16(&input, 8000, 48000);
141
142 assert!(output.len() >= 25);
143 }
144
145 #[test]
146 fn test_resample_single_sample() {
147 let input: Vec<f32> = vec![0.5];
148 let output = resample_linear(&input, 8000, 48000);
149
150 assert!(!output.is_empty());
152 assert!(output.iter().all(|&v| (v - 0.5).abs() < 0.001));
153 }
154
155 #[test]
156 fn test_resample_boundary_values() {
157 let input: Vec<f32> = vec![-1.0, 1.0, -1.0, 1.0];
158 let output = resample_linear(&input, 8000, 16000);
159
160 for v in &output {
162 assert!(*v >= -1.0 && *v <= 1.0);
163 }
164 }
165
166 #[test]
167 fn test_f32_to_i16_clipping() {
168 let input = vec![1.5, -1.5, 2.0, -2.0];
170 let output = f32_to_i16(&input);
171
172 assert_eq!(output[0], i16::MAX);
174 assert_eq!(output[1], i16::MIN);
175 assert_eq!(output[2], i16::MAX);
176 assert_eq!(output[3], i16::MIN);
177 }
178
179 #[test]
180 fn test_i16_to_f32_range() {
181 let input = vec![i16::MIN, 0, i16::MAX];
182 let output = i16_to_f32(&input);
183
184 assert!(output[0] <= -0.99 && output[0] >= -1.0);
185 assert!((output[1]).abs() < 0.001);
186 assert!(output[2] >= 0.99 && output[2] <= 1.0);
187 }
188
189 #[test]
190 fn test_resample_various_ratios() {
191 let input: Vec<f32> = (0..100).map(|i| (i as f32 / 100.0) * 2.0 - 1.0).collect();
192
193 let rates = [
195 (8000, 16000),
196 (16000, 8000),
197 (8000, 44100),
198 (44100, 8000),
199 (48000, 44100),
200 (44100, 48000),
201 ];
202
203 for (from, to) in rates {
204 let output = resample_linear(&input, from, to);
205 let expected_len = (input.len() as f64 * to as f64 / from as f64) as usize;
206 assert!(
208 (output.len() as i64 - expected_len as i64).abs() <= 1,
209 "Resample {}->{}: expected ~{}, got {}",
210 from,
211 to,
212 expected_len,
213 output.len()
214 );
215 }
216 }
217
218 #[test]
219 fn test_resample_preserves_dc() {
220 let input: Vec<f32> = vec![0.5; 100];
222 let output = resample_linear(&input, 8000, 48000);
223
224 for v in &output {
225 assert!((v - 0.5).abs() < 0.001, "DC not preserved: {}", v);
226 }
227 }
228}