libflo_audio/
reader.rs

1use crate::core::{
2    ChannelData, FloFile, FloResult, Frame, FrameType, Header, ResidualEncoding, TocEntry,
3};
4use crate::MAGIC;
5
6/// binary reader for flo format
7pub struct Reader;
8
9impl Reader {
10    /// new reader
11    pub fn new() -> Self {
12        Reader
13    }
14
15    /// read and parse a flo file
16    pub fn read(&self, data: &[u8]) -> FloResult<FloFile> {
17        let mut cursor = Cursor::new(data);
18
19        // magic
20        let magic = cursor.read_bytes(4)?;
21        if magic != MAGIC {
22            return Err("Invalid flo file: bad magic".to_string());
23        }
24
25        // header
26        let header = self.read_header(&mut cursor)?;
27
28        // toc
29        let toc = self.read_toc(&mut cursor, header.toc_size as usize)?;
30
31        // Read DATA chunk
32        let frames = self.read_data_chunk(
33            &mut cursor,
34            header.data_size as usize,
35            header.channels,
36            &toc,
37        )?;
38
39        // Skip EXTRA chunk
40        cursor.skip(header.extra_size as usize)?;
41
42        // Read META chunk
43        let metadata = cursor.read_bytes(header.meta_size as usize)?;
44
45        Ok(FloFile {
46            header,
47            toc,
48            frames,
49            extra: vec![],
50            metadata,
51        })
52    }
53
54    fn read_header(&self, cursor: &mut Cursor) -> FloResult<Header> {
55        Ok(Header {
56            version_major: cursor.read_u8()?,
57            version_minor: cursor.read_u8()?,
58            flags: cursor.read_u16_le()?,
59            sample_rate: cursor.read_u32_le()?,
60            channels: cursor.read_u8()?,
61            bit_depth: cursor.read_u8()?,
62            total_frames: cursor.read_u64_le()?,
63            compression_level: cursor.read_u8()?,
64            data_crc32: {
65                cursor.skip(3)?; // reserved
66                cursor.read_u32_le()?
67            },
68            header_size: cursor.read_u64_le()?,
69            toc_size: cursor.read_u64_le()?,
70            data_size: cursor.read_u64_le()?,
71            extra_size: cursor.read_u64_le()?,
72            meta_size: cursor.read_u64_le()?,
73        })
74    }
75
76    fn read_toc(&self, cursor: &mut Cursor, toc_size: usize) -> FloResult<Vec<TocEntry>> {
77        if toc_size < 4 {
78            return Ok(vec![]);
79        }
80
81        let num_entries = cursor.read_u32_le()? as usize;
82
83        if num_entries > 100_000 {
84            return Err("Invalid TOC: too many entries".to_string());
85        }
86
87        let mut entries = Vec::with_capacity(num_entries);
88
89        for _ in 0..num_entries {
90            entries.push(TocEntry {
91                frame_index: cursor.read_u32_le()?,
92                byte_offset: cursor.read_u64_le()?,
93                frame_size: cursor.read_u32_le()?,
94                timestamp_ms: cursor.read_u32_le()?,
95            });
96        }
97
98        Ok(entries)
99    }
100
101    fn read_data_chunk(
102        &self,
103        cursor: &mut Cursor,
104        data_size: usize,
105        channels: u8,
106        toc: &[TocEntry],
107    ) -> FloResult<Vec<Frame>> {
108        let data_start = cursor.pos;
109        let data_end = cursor.pos + data_size;
110        let mut frames = Vec::with_capacity(toc.len());
111
112        for toc_entry in toc.iter() {
113            let frame_start = data_start + toc_entry.byte_offset as usize;
114
115            if frame_start >= data_end {
116                break;
117            }
118
119            cursor.pos = frame_start;
120            let frame_size = toc_entry.frame_size as usize;
121
122            let frame = self.read_frame(cursor, channels, frame_size)?;
123            frames.push(frame);
124        }
125
126        cursor.pos = data_end;
127        Ok(frames)
128    }
129
130    fn read_frame(&self, cursor: &mut Cursor, channels: u8, frame_size: usize) -> FloResult<Frame> {
131        let frame_start = cursor.pos;
132        let frame_end = frame_start + frame_size;
133
134        // frame header: type(1) + samples(4) + flags(1)
135        let frame_type_byte = cursor.read_u8()?;
136        let frame_samples = cursor.read_u32_le()?;
137        let flags = cursor.read_u8()?;
138
139        let frame_type = FrameType::from(frame_type_byte);
140        let mut frame = Frame::new(frame_type_byte, frame_samples);
141        frame.flags = flags;
142
143        // transform frames are one blob, others are per-channel
144        let num_channels_to_read = if frame_type == FrameType::Transform {
145            1
146        } else {
147            channels as usize
148        };
149
150        // read each channels data
151        for _ch_idx in 0..num_channels_to_read {
152            // channel size
153            let ch_size = cursor.read_u32_le()? as usize;
154            let ch_end = cursor.pos + ch_size;
155
156            let ch_data =
157                self.read_channel_data(cursor, frame_type, frame_samples as usize, ch_end)?;
158            frame.channels.push(ch_data);
159
160            // move to end of channel
161            cursor.pos = ch_end;
162        }
163
164        cursor.pos = frame_end;
165        Ok(frame)
166    }
167
168    fn read_channel_data(
169        &self,
170        cursor: &mut Cursor,
171        frame_type: FrameType,
172        frame_samples: usize,
173        channel_end: usize,
174    ) -> FloResult<ChannelData> {
175        if frame_samples > 2_000_000 {
176            return Err("Invalid frame: too many samples".to_string());
177        }
178
179        match frame_type {
180            FrameType::Silence => Ok(ChannelData::new_silence()),
181
182            FrameType::Raw => {
183                let bytes_needed = frame_samples.saturating_mul(2);
184                let available = channel_end.saturating_sub(cursor.pos);
185                let bytes_to_read = bytes_needed.min(available);
186                let residuals = cursor.read_bytes(bytes_to_read)?;
187                Ok(ChannelData::new_raw(residuals))
188            }
189
190            FrameType::Transform => {
191                // serialized mdct data
192                let remaining = channel_end.saturating_sub(cursor.pos);
193                let residuals = if remaining > 0 {
194                    cursor.read_bytes(remaining)?
195                } else {
196                    vec![]
197                };
198
199                Ok(ChannelData {
200                    predictor_coeffs: vec![],
201                    shift_bits: 0,
202                    residual_encoding: ResidualEncoding::Raw,
203                    rice_parameter: 0,
204                    residuals,
205                })
206            }
207
208            _ if frame_type.is_alpc() => {
209                // predictor order
210                let order = cursor.read_u8()? as usize;
211
212                if order > 12 {
213                    return Err("Invalid LPC order".to_string());
214                }
215
216                // predictor coeffs
217                let mut predictor_coeffs = Vec::with_capacity(order);
218                for _ in 0..order {
219                    if cursor.pos + 4 > channel_end {
220                        break;
221                    }
222                    predictor_coeffs.push(cursor.read_i32_le()?);
223                }
224
225                let shift_bits = cursor.read_u8()?;
226
227                let residual_encoding_byte = cursor.read_u8()?;
228                let residual_encoding = ResidualEncoding::from(residual_encoding_byte);
229
230                // rice param only for rice encoding
231                let rice_parameter = if residual_encoding == ResidualEncoding::Rice {
232                    cursor.read_u8()?
233                } else {
234                    0
235                };
236
237                // rest is residuals
238                let remaining = channel_end.saturating_sub(cursor.pos);
239                let residuals = if remaining > 0 {
240                    cursor.read_bytes(remaining)?
241                } else {
242                    vec![]
243                };
244
245                Ok(ChannelData {
246                    predictor_coeffs,
247                    shift_bits,
248                    residual_encoding,
249                    rice_parameter,
250                    residuals,
251                })
252            }
253
254            _ => Ok(ChannelData::new_silence()),
255        }
256    }
257}
258
259impl Default for Reader {
260    fn default() -> Self {
261        Self::new()
262    }
263}
264
265// cursor helper
266
267struct Cursor<'a> {
268    data: &'a [u8],
269    pos: usize,
270}
271
272impl<'a> Cursor<'a> {
273    fn new(data: &'a [u8]) -> Self {
274        Cursor { data, pos: 0 }
275    }
276
277    fn read_bytes(&mut self, count: usize) -> FloResult<Vec<u8>> {
278        if self.pos + count > self.data.len() {
279            return Err("Unexpected end of file".to_string());
280        }
281        let bytes = self.data[self.pos..self.pos + count].to_vec();
282        self.pos += count;
283        Ok(bytes)
284    }
285
286    fn skip(&mut self, count: usize) -> FloResult<()> {
287        self.pos = (self.pos + count).min(self.data.len());
288        Ok(())
289    }
290
291    fn read_u8(&mut self) -> FloResult<u8> {
292        if self.pos >= self.data.len() {
293            return Err("Unexpected end of file".to_string());
294        }
295        let val = self.data[self.pos];
296        self.pos += 1;
297        Ok(val)
298    }
299
300    fn read_u16_le(&mut self) -> FloResult<u16> {
301        let bytes = self.read_bytes(2)?;
302        Ok(u16::from_le_bytes([bytes[0], bytes[1]]))
303    }
304
305    fn read_u32_le(&mut self) -> FloResult<u32> {
306        let bytes = self.read_bytes(4)?;
307        Ok(u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]))
308    }
309
310    fn read_i32_le(&mut self) -> FloResult<i32> {
311        let bytes = self.read_bytes(4)?;
312        Ok(i32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]))
313    }
314
315    fn read_u64_le(&mut self) -> FloResult<u64> {
316        let bytes = self.read_bytes(8)?;
317        Ok(u64::from_le_bytes([
318            bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7],
319        ]))
320    }
321}