Skip to main content

libflo_audio/lossless/
decoder.rs

1use crate::core::audio_constants::i32_to_f32;
2use crate::core::types::{ChannelData, FloFile};
3use crate::{core::rice, FloResult, Reader};
4use alloc::vec;
5use alloc::vec::Vec;
6
7/// audio decoder for flo format
8pub struct Decoder;
9
10impl Decoder {
11    pub fn new() -> Self {
12        Decoder
13    }
14
15    /// decode flo file to samples
16    pub fn decode(&self, data: &[u8]) -> FloResult<Vec<f32>> {
17        let reader = Reader::new();
18        let file = reader.read(data)?;
19        self.decode_file(&file)
20    }
21
22    /// decode from parsed file
23    pub fn decode_file(&self, file: &FloFile) -> FloResult<Vec<f32>> {
24        let channels = file.header.channels as usize;
25        let halved_mid_side = file.header.version_minor >= 2;
26        let mut all_samples: Vec<Vec<i32>> = vec![vec![]; channels];
27
28        for frame in &file.frames {
29            let use_mid_side = channels == 2 && (frame.flags & 0x01) != 0;
30
31            let mut frame_channels: Vec<Vec<i32>> = Vec::with_capacity(channels);
32
33            for ch_data in &frame.channels {
34                let samples = self.decode_channel_int(ch_data, frame.frame_samples as usize)?;
35                frame_channels.push(samples);
36            }
37
38            // mid-side to left-right
39            if use_mid_side && frame_channels.len() == 2 {
40                let (left, right) =
41                    self.decode_mid_side(&frame_channels[0], &frame_channels[1], halved_mid_side);
42                all_samples[0].extend(left);
43                all_samples[1].extend(right);
44            } else {
45                for (ch_idx, samples) in frame_channels.into_iter().enumerate() {
46                    if ch_idx < channels {
47                        all_samples[ch_idx].extend(samples);
48                    }
49                }
50            }
51        }
52
53        // interleave and convert to f32
54        let max_len = all_samples.iter().map(|v| v.len()).max().unwrap_or(0);
55        let mut interleaved = Vec::with_capacity(max_len * channels);
56
57        // Fast path for stereo (most common case)
58        if channels == 2 && all_samples[0].len() == all_samples[1].len() {
59            let left = &all_samples[0];
60            let right = &all_samples[1];
61            for i in 0..left.len() {
62                interleaved.push(i32_to_f32(left[i]));
63                interleaved.push(i32_to_f32(right[i]));
64            }
65        } else {
66            // General case for mono or mismatched lengths
67            for i in 0..max_len {
68                for ch in 0..channels {
69                    let sample = all_samples[ch].get(i).copied().unwrap_or(0);
70                    interleaved.push(i32_to_f32(sample));
71                }
72            }
73        }
74
75        Ok(interleaved)
76    }
77
78    /// Convert mid-side back to left-right
79    fn decode_mid_side(&self, mid: &[i32], side: &[i32], halved: bool) -> (Vec<i32>, Vec<i32>) {
80        if halved {
81            let left: Vec<i32> = mid
82                .iter()
83                .zip(side.iter())
84                .map(|(&m, &s)| m + ((s + (s & 1)) >> 1))
85                .collect();
86            let right: Vec<i32> = mid
87                .iter()
88                .zip(side.iter())
89                .map(|(&m, &s)| m - (s >> 1))
90                .collect();
91            (left, right)
92        } else {
93            let left: Vec<i32> = mid
94                .iter()
95                .zip(side.iter())
96                .map(|(&m, &s)| (m + s) / 2)
97                .collect();
98            let right: Vec<i32> = mid
99                .iter()
100                .zip(side.iter())
101                .map(|(&m, &s)| (m - s) / 2)
102                .collect();
103            (left, right)
104        }
105    }
106
107    /// Decode a single channel to integers
108    fn decode_channel_int(
109        &self,
110        ch_data: &ChannelData,
111        frame_samples: usize,
112    ) -> FloResult<Vec<i32>> {
113        let has_coeffs = !ch_data.predictor_coeffs.is_empty();
114        let has_residuals = !ch_data.residuals.is_empty();
115        let shift_bits = ch_data.shift_bits;
116
117        // Check for fixed predictor marker: shift_bits >= 128 means fixed order (128 + order)
118        let is_fixed_predictor = !has_coeffs && has_residuals && shift_bits >= 128;
119
120        if is_fixed_predictor {
121            // Fixed predictor: order stored as (128 + order)
122            let fixed_order = (shift_bits - 128) as usize;
123
124            let residuals =
125                rice::decode_i32(&ch_data.residuals, ch_data.rice_parameter, frame_samples);
126
127            return Ok(self.reconstruct_fixed(fixed_order, &residuals, frame_samples));
128        }
129
130        if has_coeffs {
131            // LPC decoding with stored coefficients
132            let residuals =
133                rice::decode_i32(&ch_data.residuals, ch_data.rice_parameter, frame_samples);
134
135            let order = ch_data.predictor_coeffs.len();
136
137            let samples = self.reconstruct_lpc_int(
138                &ch_data.predictor_coeffs,
139                &residuals,
140                shift_bits,
141                order,
142                frame_samples,
143            );
144
145            return Ok(samples);
146        }
147
148        if has_residuals {
149            // Raw PCM
150            let mut samples = Vec::with_capacity(frame_samples);
151            for chunk in ch_data.residuals.chunks(2) {
152                if chunk.len() == 2 {
153                    samples.push(i16::from_le_bytes([chunk[0], chunk[1]]) as i32);
154                }
155            }
156            while samples.len() < frame_samples {
157                samples.push(0);
158            }
159            return Ok(samples);
160        }
161
162        // Silence
163        Ok(vec![0; frame_samples])
164    }
165
166    /// Reconstruct from LPC prediction
167    #[inline]
168    fn reconstruct_lpc_int(
169        &self,
170        coeffs: &[i32],
171        residuals: &[i32],
172        shift: u8,
173        order: usize,
174        target_len: usize,
175    ) -> Vec<i32> {
176        let mut samples = Vec::with_capacity(target_len);
177        let actual_len = target_len.min(residuals.len());
178
179        // Warmup samples from residuals (no prediction needed)
180        let warmup_len = order.min(actual_len);
181        samples.extend_from_slice(&residuals[..warmup_len]);
182
183        // Reconstruct remaining samples using LPC prediction
184        // This is the hot loop - keep it simple and predictable
185        for i in order..actual_len {
186            let mut prediction: i64 = 0;
187
188            // Unrolled inner loop for common orders
189            // Access pattern: samples[i-1], samples[i-2], ..., samples[i-order]
190            for j in 0..order {
191                prediction += (coeffs[j] as i64) * (samples[i - j - 1] as i64);
192            }
193
194            samples.push((prediction >> shift) as i32 + residuals[i]);
195        }
196
197        // Pad if needed
198        samples.resize(target_len, 0);
199        samples
200    }
201
202    /// Reconstruct from fixed predictor
203    fn reconstruct_fixed(&self, order: usize, residuals: &[i32], target_len: usize) -> Vec<i32> {
204        let mut samples = Vec::with_capacity(target_len);
205
206        if residuals.is_empty() {
207            return vec![0; target_len];
208        }
209
210        match order {
211            0 => {
212                // No prediction - residuals are samples
213                samples.extend_from_slice(residuals);
214            }
215            1 => {
216                // s[i] = r[i] + s[i-1]
217                samples.push(residuals[0]);
218                for i in 1..residuals.len().min(target_len) {
219                    samples.push(residuals[i].wrapping_add(samples[i - 1]));
220                }
221            }
222            2 => {
223                // s[i] = r[i] + 2*s[i-1] - s[i-2]
224                if !residuals.is_empty() {
225                    samples.push(residuals[0]);
226                }
227                if residuals.len() > 1 {
228                    samples.push(residuals[1].wrapping_add(samples[0]));
229                }
230                for i in 2..residuals.len().min(target_len) {
231                    let pred = (2i64 * samples[i - 1] as i64 - samples[i - 2] as i64) as i32;
232                    samples.push(residuals[i].wrapping_add(pred));
233                }
234            }
235            3 => {
236                // s[i] = r[i] + 3*s[i-1] - 3*s[i-2] + s[i-3]
237                if !residuals.is_empty() {
238                    samples.push(residuals[0]);
239                }
240                if residuals.len() > 1 {
241                    samples.push(residuals[1].wrapping_add(samples[0]));
242                }
243                if residuals.len() > 2 {
244                    let pred = (2i64 * samples[1] as i64 - samples[0] as i64) as i32;
245                    samples.push(residuals[2].wrapping_add(pred));
246                }
247                for i in 3..residuals.len().min(target_len) {
248                    let pred = (3i64 * samples[i - 1] as i64 - 3i64 * samples[i - 2] as i64
249                        + samples[i - 3] as i64) as i32;
250                    samples.push(residuals[i].wrapping_add(pred));
251                }
252            }
253            4 => {
254                // s[i] = r[i] + 4*s[i-1] - 6*s[i-2] + 4*s[i-3] - s[i-4]
255                if !residuals.is_empty() {
256                    samples.push(residuals[0]);
257                }
258                if residuals.len() > 1 {
259                    samples.push(residuals[1].wrapping_add(samples[0]));
260                }
261                if residuals.len() > 2 {
262                    let pred = (2i64 * samples[1] as i64 - samples[0] as i64) as i32;
263                    samples.push(residuals[2].wrapping_add(pred));
264                }
265                if residuals.len() > 3 {
266                    let pred = (3i64 * samples[2] as i64 - 3i64 * samples[1] as i64
267                        + samples[0] as i64) as i32;
268                    samples.push(residuals[3].wrapping_add(pred));
269                }
270                for i in 4..residuals.len().min(target_len) {
271                    let pred = (4i64 * samples[i - 1] as i64 - 6i64 * samples[i - 2] as i64
272                        + 4i64 * samples[i - 3] as i64
273                        - samples[i - 4] as i64) as i32;
274                    samples.push(residuals[i].wrapping_add(pred));
275                }
276            }
277            _ => {
278                // Unknown order, just use residuals
279                samples.extend_from_slice(residuals);
280            }
281        }
282
283        // Pad if needed
284        while samples.len() < target_len {
285            samples.push(0);
286        }
287
288        samples
289    }
290}
291
292impl Default for Decoder {
293    fn default() -> Self {
294        Self::new()
295    }
296}