1use crate::core::audio_constants::f32_to_i32;
2use crate::core::{ChannelData, Frame, FrameType, ResidualEncoding};
3use crate::{core::rice, FloResult, Writer};
4use alloc::vec;
5use alloc::vec::Vec;
6
7use super::lpc::{
8 autocorr_int, calc_residuals_int, fixed_predictor_residuals, levinson_durbin_int,
9};
10
11pub struct Encoder {
12 sample_rate: u32,
13 channels: u8,
14 bit_depth: u8,
15 compression_level: u8,
16}
17
18impl Encoder {
19 pub fn new(sample_rate: u32, channels: u8, bit_depth: u8) -> Self {
20 Encoder {
21 sample_rate,
22 channels,
23 bit_depth,
24 compression_level: 5,
25 }
26 }
27
28 pub fn with_compression(mut self, level: u8) -> Self {
29 self.compression_level = level.min(9);
30 self
31 }
32
33 pub fn encode(&self, samples: &[f32], metadata: &[u8]) -> FloResult<Vec<u8>> {
35 if self.sample_rate == 0 {
36 return Err("Sample rate must be greater than zero".into());
37 }
38 if self.channels == 0 {
39 return Err("Channel count must be greater than zero".into());
40 }
41 if !samples.len().is_multiple_of(self.channels as usize) {
42 return Err("Interleaved samples must contain a complete final frame".into());
43 }
44
45 let samples_per_frame = self.sample_rate as usize;
46 let frames = self.encode_frames(samples, samples_per_frame);
47
48 let writer = Writer::new();
49 writer.write(
50 self.sample_rate,
51 self.channels,
52 self.bit_depth,
53 self.compression_level,
54 &frames,
55 metadata,
56 )
57 }
58
59 fn encode_frames(&self, samples: &[f32], samples_per_frame: usize) -> Vec<Frame> {
60 let total_samples = samples.len() / (self.channels as usize);
61 let num_frames = total_samples.div_ceil(samples_per_frame);
62
63 let mut frames = Vec::with_capacity(num_frames);
64
65 for frame_idx in 0..num_frames {
66 let start = frame_idx * samples_per_frame * (self.channels as usize);
67 let end =
68 ((frame_idx + 1) * samples_per_frame * (self.channels as usize)).min(samples.len());
69
70 let frame_samples = &samples[start..end];
71 let frame = self.encode_frame(frame_samples);
72 frames.push(frame);
73 }
74
75 frames
76 }
77
78 fn encode_frame(&self, samples: &[f32]) -> Frame {
79 let num_samples = samples.len() / (self.channels as usize);
80
81 if samples.iter().all(|&s| s.abs() < 1e-7) {
83 let mut frame = Frame::new(FrameType::Silence as u8, num_samples as u32);
84 for _ in 0..self.channels {
85 frame.channels.push(ChannelData::new_silence());
86 }
87 return frame;
88 }
89
90 let samples_i32: Vec<i32> = samples.iter().map(|&s| f32_to_i32(s)).collect();
92
93 let mut channel_data: Vec<Vec<i32>> = (0..self.channels as usize)
95 .map(|ch| {
96 samples_i32
97 .iter()
98 .skip(ch)
99 .step_by(self.channels as usize)
100 .copied()
101 .collect()
102 })
103 .collect();
104
105 let use_mid_side = self.channels == 2 && self.should_use_mid_side(&channel_data);
107 if use_mid_side {
108 let (mid, side) = self.to_mid_side(&channel_data[0], &channel_data[1]);
109 channel_data[0] = mid;
110 channel_data[1] = side;
111 }
112
113 let lpc_order = self.lpc_order_from_level();
115 let mut encoded_channels = Vec::with_capacity(self.channels as usize);
116 let mut all_raw = true;
117
118 for ch_samples in &channel_data {
119 let (ch_data, order_used, used_raw) = self.encode_channel_int(ch_samples, lpc_order);
120 if !used_raw || order_used > 0 {
121 all_raw = false;
122 }
123 encoded_channels.push(ch_data);
124 }
125
126 let frame_type = if all_raw {
128 FrameType::Raw
129 } else {
130 FrameType::from_order(lpc_order)
131 };
132
133 let mut frame = Frame::new(frame_type as u8, num_samples as u32);
134 if use_mid_side {
136 frame.flags |= 0x01; }
138 frame.channels = encoded_channels;
139 frame
140 }
141
142 fn should_use_mid_side(&self, channels: &[Vec<i32>]) -> bool {
144 if channels.len() != 2 {
145 return false;
146 }
147
148 let left = &channels[0];
149 let right = &channels[1];
150
151 let mut var_l: i64 = 0;
153 let mut var_r: i64 = 0;
154 let mut var_side: i64 = 0;
155
156 for (&l, &r) in left.iter().zip(right.iter()) {
157 var_l += (l as i64) * (l as i64);
158 var_r += (r as i64) * (r as i64);
159 let side = l - r;
160 var_side += (side as i64) * (side as i64);
161 }
162
163 var_side < (var_l + var_r) / 2
165 }
166
167 fn to_mid_side(&self, left: &[i32], right: &[i32]) -> (Vec<i32>, Vec<i32>) {
169 let mid: Vec<i32> = left
170 .iter()
171 .zip(right.iter())
172 .map(|(&l, &r)| (l + r) >> 1)
173 .collect();
174 let side: Vec<i32> = left
175 .iter()
176 .zip(right.iter())
177 .map(|(&l, &r)| l - r)
178 .collect();
179 (mid, side)
180 }
181
182 #[allow(clippy::type_complexity)]
184 fn encode_channel_int(&self, samples: &[i32], max_order: usize) -> (ChannelData, usize, bool) {
185 if samples.is_empty() {
186 return (ChannelData::new_silence(), 0, false);
187 }
188
189 let mut best_data: Option<ChannelData> = None;
191 let mut best_size = usize::MAX;
192 let mut best_order = 0;
193 let mut best_used_raw = false;
194
195 let raw_fits_i16 = samples
201 .iter()
202 .all(|&s| (i32::from(i16::MIN)..=i32::from(i16::MAX)).contains(&s));
203 if raw_fits_i16 {
204 let raw = self.encode_raw(samples);
205 let raw_size = raw.residuals.len();
206 if raw_size < best_size {
207 best_size = raw_size;
208 best_data = Some(raw);
209 best_order = 0;
210 best_used_raw = true;
211 }
212 }
213
214 for order in 0..=(4).min(max_order) {
216 if let Some((data, size)) = self.try_fixed_predictor(samples, order) {
217 if size < best_size {
218 best_size = size;
219 best_data = Some(data);
220 best_order = order;
221 best_used_raw = false;
222 }
223 }
224 }
225
226 if self.compression_level >= 3 && max_order > 4 {
228 for order in 5..=max_order {
229 if let Some((data, size)) = self.try_lpc_predictor(samples, order) {
230 if size < best_size {
231 best_size = size;
232 best_data = Some(data);
233 best_order = order;
234 best_used_raw = false;
235 }
236 }
237 }
238 }
239
240 (best_data.unwrap(), best_order, best_used_raw)
241 }
242
243 fn encode_raw(&self, samples: &[i32]) -> ChannelData {
245 let raw_bytes: Vec<u8> = samples
246 .iter()
247 .flat_map(|&s| (s as i16).to_le_bytes().to_vec())
248 .collect();
249 ChannelData::new_raw(raw_bytes)
250 }
251
252 fn try_fixed_predictor(&self, samples: &[i32], order: usize) -> Option<(ChannelData, usize)> {
254 if order > 4 {
255 return None;
256 }
257
258 let residuals = fixed_predictor_residuals(samples, order);
259
260 let k = rice::estimate_rice_parameter_i32(&residuals);
262 let encoded = rice::encode_i32(&residuals, k);
263
264 let ch_data = ChannelData {
267 predictor_coeffs: vec![], shift_bits: (128 + order) as u8, residual_encoding: ResidualEncoding::Rice,
270 rice_parameter: k,
271 residuals: encoded.clone(),
272 };
273
274 Some((ch_data, encoded.len()))
275 }
276
277 fn try_lpc_predictor(&self, samples: &[i32], order: usize) -> Option<(ChannelData, usize)> {
279 if samples.len() <= order {
280 return None;
281 }
282
283 let autocorr = autocorr_int(samples, order);
285
286 let (coeffs_fp, shift) = levinson_durbin_int(&autocorr, order)?;
288
289 let residuals = calc_residuals_int(samples, &coeffs_fp, shift, order);
291
292 let max_res = residuals.iter().map(|&r| r.abs()).max().unwrap_or(0);
294 if max_res > 1_000_000 {
295 return None; }
297
298 let k = rice::estimate_rice_parameter_i32(&residuals);
300 let encoded = rice::encode_i32(&residuals, k);
301
302 let ch_data = ChannelData {
303 predictor_coeffs: coeffs_fp,
304 shift_bits: shift,
305 residual_encoding: ResidualEncoding::Rice,
306 rice_parameter: k,
307 residuals: encoded.clone(),
308 };
309
310 Some((ch_data, encoded.len()))
311 }
312
313 fn lpc_order_from_level(&self) -> usize {
314 match self.compression_level {
315 0 => 0, 1 => 2,
317 2 => 4,
318 3 => 4,
319 4 => 6,
320 5 => 8,
321 6 => 8,
322 7 => 10,
323 8 => 12,
324 _ => 12,
325 }
326 }
327}
328
329impl Default for Encoder {
330 fn default() -> Self {
331 Encoder::new(44100, 1, 16)
332 }
333}