libflo_audio/streaming/
encoder.rs

1use crate::core::{ChannelData, FloResult, FrameType};
2use crate::lossless::Encoder;
3use crate::{compute_crc32, Reader, MAGIC};
4
5pub struct StreamingEncoder {
6    sample_rate: u32,
7    channels: u8,
8    bit_depth: u8,
9    compression_level: u8,
10    sample_buffer: Vec<f32>,
11    samples_per_frame: usize,
12    pending_frames: Vec<EncodedFrame>,
13    encoder: Encoder,
14    total_samples: u64,
15    frame_index: u32,
16}
17
18/// An encoded frame ready for transmission
19#[derive(Debug, Clone)]
20pub struct EncodedFrame {
21    /// Frame index
22    pub index: u32,
23    /// Timestamp in milliseconds
24    pub timestamp_ms: u32,
25    /// Encoded frame data
26    pub data: Vec<u8>,
27    /// Number of samples in this frame
28    pub samples: u32,
29}
30
31impl StreamingEncoder {
32    /// Create a new streaming encoder
33    pub fn new(sample_rate: u32, channels: u8, bit_depth: u8) -> Self {
34        let samples_per_frame = sample_rate as usize;
35
36        Self {
37            sample_rate,
38            channels,
39            bit_depth,
40            compression_level: 5,
41            sample_buffer: Vec::with_capacity(samples_per_frame * channels as usize * 2),
42            samples_per_frame,
43            pending_frames: Vec::new(),
44            encoder: Encoder::new(sample_rate, channels, bit_depth),
45            total_samples: 0,
46            frame_index: 0,
47        }
48    }
49
50    /// Set compression level (0-9)
51    pub fn with_compression(mut self, level: u8) -> Self {
52        self.compression_level = level.min(9);
53        self.encoder =
54            Encoder::new(self.sample_rate, self.channels, self.bit_depth).with_compression(level);
55        self
56    }
57
58    /// Get number of pending samples in buffer
59    pub fn pending_samples(&self) -> usize {
60        self.sample_buffer.len() / self.channels as usize
61    }
62
63    /// Get number of encoded frames ready
64    pub fn pending_frames(&self) -> usize {
65        self.pending_frames.len()
66    }
67
68    /// Push samples to the encoder
69    ///
70    /// Samples should be interleaved if multi-channel
71    pub fn push_samples(&mut self, samples: &[f32]) -> FloResult<()> {
72        self.sample_buffer.extend_from_slice(samples);
73        self.try_encode_frames()?;
74        Ok(())
75    }
76
77    /// Get next encoded frame if available
78    pub fn next_frame(&mut self) -> Option<EncodedFrame> {
79        if self.pending_frames.is_empty() {
80            None
81        } else {
82            Some(self.pending_frames.remove(0))
83        }
84    }
85
86    /// Flush remaining samples (may produce a partial frame)
87    pub fn flush(&mut self) -> FloResult<Option<EncodedFrame>> {
88        if self.sample_buffer.is_empty() {
89            return Ok(None);
90        }
91
92        let samples_per_channel = self.sample_buffer.len() / self.channels as usize;
93        let timestamp_ms = (self.total_samples as f64 / self.sample_rate as f64 * 1000.0) as u32;
94
95        let frame_data = self.encode_frame_data(&self.sample_buffer)?;
96
97        let encoded = EncodedFrame {
98            index: self.frame_index,
99            timestamp_ms,
100            data: frame_data,
101            samples: samples_per_channel as u32,
102        };
103
104        self.total_samples += samples_per_channel as u64;
105        self.frame_index += 1;
106        self.sample_buffer.clear();
107
108        Ok(Some(encoded))
109    }
110
111    /// Build a complete flo™ file from accumulated frames
112    pub fn finalize(&mut self, metadata: &[u8]) -> FloResult<Vec<u8>> {
113        if let Some(frame) = self.flush()? {
114            self.pending_frames.push(frame);
115        }
116
117        // Build TOC
118        let mut toc_data = Vec::new();
119        let num_frames = self.pending_frames.len() as u32;
120        toc_data.extend_from_slice(&num_frames.to_le_bytes());
121
122        let mut byte_offset: u64 = 0;
123        for frame in &self.pending_frames {
124            toc_data.extend_from_slice(&frame.index.to_le_bytes());
125            toc_data.extend_from_slice(&byte_offset.to_le_bytes());
126            toc_data.extend_from_slice(&(frame.data.len() as u32).to_le_bytes());
127            toc_data.extend_from_slice(&frame.timestamp_ms.to_le_bytes());
128            byte_offset += frame.data.len() as u64;
129        }
130
131        // Build DATA
132        let mut data_chunk = Vec::new();
133        for frame in &self.pending_frames {
134            data_chunk.extend_from_slice(&frame.data);
135        }
136
137        let data_crc32 = compute_crc32(&data_chunk);
138
139        let header_size: u64 = 66;
140        let toc_size = toc_data.len() as u64;
141        let data_size = data_chunk.len() as u64;
142        let extra_size: u64 = 0;
143        let meta_size = metadata.len() as u64;
144
145        let mut output = Vec::new();
146
147        // Magic
148        output.extend_from_slice(&MAGIC);
149
150        // Header
151        output.push(1); // version_major
152        output.push(1); // version_minor
153        output.extend_from_slice(&0u16.to_le_bytes()); // flags
154        output.extend_from_slice(&self.sample_rate.to_le_bytes());
155        output.push(self.channels);
156        output.push(self.bit_depth);
157        output.extend_from_slice(&(self.pending_frames.len() as u64).to_le_bytes());
158        output.push(self.compression_level);
159        output.extend_from_slice(&[0u8; 3]); // reserved
160        output.extend_from_slice(&data_crc32.to_le_bytes());
161        output.extend_from_slice(&header_size.to_le_bytes());
162        output.extend_from_slice(&toc_size.to_le_bytes());
163        output.extend_from_slice(&data_size.to_le_bytes());
164        output.extend_from_slice(&extra_size.to_le_bytes());
165        output.extend_from_slice(&meta_size.to_le_bytes());
166
167        // TOC
168        output.extend_from_slice(&toc_data);
169
170        // DATA
171        output.extend_from_slice(&data_chunk);
172
173        // META
174        output.extend_from_slice(metadata);
175
176        self.pending_frames.clear();
177
178        Ok(output)
179    }
180
181    // ========================================================================
182    // Internal methods
183    // ========================================================================
184
185    fn try_encode_frames(&mut self) -> FloResult<()> {
186        let frame_samples = self.samples_per_frame * self.channels as usize;
187
188        while self.sample_buffer.len() >= frame_samples {
189            let frame_data: Vec<f32> = self.sample_buffer.drain(..frame_samples).collect();
190            let timestamp_ms =
191                (self.total_samples as f64 / self.sample_rate as f64 * 1000.0) as u32;
192
193            let encoded_data = self.encode_frame_data(&frame_data)?;
194
195            self.pending_frames.push(EncodedFrame {
196                index: self.frame_index,
197                timestamp_ms,
198                data: encoded_data,
199                samples: self.samples_per_frame as u32,
200            });
201
202            self.total_samples += self.samples_per_frame as u64;
203            self.frame_index += 1;
204        }
205
206        Ok(())
207    }
208
209    fn encode_frame_data(&self, samples: &[f32]) -> FloResult<Vec<u8>> {
210        let temp_flo = self.encoder.encode(samples, &[])?;
211
212        let reader = Reader::new();
213        let file = reader.read(&temp_flo)?;
214
215        if file.frames.is_empty() {
216            return Err("No frames encoded".to_string());
217        }
218
219        let frame = &file.frames[0];
220        let mut data = Vec::new();
221
222        // Frame header
223        data.push(frame.frame_type);
224        data.extend_from_slice(&frame.frame_samples.to_le_bytes());
225        data.push(frame.flags);
226
227        // Channel data
228        for ch in &frame.channels {
229            let ch_data = self.serialize_channel(ch, FrameType::from(frame.frame_type));
230            data.extend_from_slice(&(ch_data.len() as u32).to_le_bytes());
231            data.extend_from_slice(&ch_data);
232        }
233
234        Ok(data)
235    }
236
237    fn serialize_channel(&self, ch: &ChannelData, frame_type: FrameType) -> Vec<u8> {
238        match frame_type {
239            FrameType::Silence => vec![],
240            FrameType::Raw | FrameType::Transform => ch.residuals.clone(),
241            _ => {
242                let mut data = Vec::new();
243                data.push(ch.rice_parameter);
244                for &coeff in &ch.predictor_coeffs {
245                    data.extend_from_slice(&coeff.to_le_bytes());
246                }
247                data.extend_from_slice(&ch.residuals);
248                data
249            }
250        }
251    }
252}