1use super::mdct::{
2 BlockSize, Mdct, WindowType, LONG_BLOCK_SIZE, SHORTS_PER_GROUP, SHORT_BLOCK_SIZE,
3 SHORT_GROUP_OFFSET,
4};
5use super::psychoacoustic::{PsychoacousticModel, NUM_BARK_BANDS};
6use crate::core::{ChannelData, Frame, FrameType, ResidualEncoding, I16_MAX_F32, I16_MIN_F32};
7use alloc::vec;
8use alloc::vec::Vec;
9
10const ATTACK_RATIO: f32 = 8.0;
13const DETECTOR_FLOOR_FRACTION: f32 = 0.05;
16const HOP_SIZE: usize = LONG_BLOCK_SIZE / 2;
18
19pub struct TransformEncoder {
21 sample_rate: u32,
23 channels: u8,
25 mdct: Mdct,
27 psy_models: Vec<PsychoacousticModel>,
29 short_psy_models: Vec<PsychoacousticModel>,
31 quality: f32,
33}
34
35#[derive(Debug, Clone)]
37pub struct TransformFrame {
38 pub coefficients: Vec<Vec<i16>>,
40 pub scale_factors: Vec<Vec<f32>>,
42 pub block_size: BlockSize,
44 pub num_samples: usize,
46}
47
48impl TransformEncoder {
49 pub fn new(sample_rate: u32, channels: u8, quality: f32) -> Self {
51 let mdct = Mdct::new(channels as usize, WindowType::Vorbis);
52 let psy_models: Vec<_> = (0..channels)
53 .map(|_| PsychoacousticModel::new(sample_rate, LONG_BLOCK_SIZE))
54 .collect();
55 let short_psy_models: Vec<_> = (0..channels)
56 .map(|_| PsychoacousticModel::new(sample_rate, SHORT_BLOCK_SIZE))
57 .collect();
58
59 Self {
60 sample_rate,
61 channels,
62 mdct,
63 psy_models,
64 short_psy_models,
65 quality: quality.clamp(0.0, 1.0),
66 }
67 }
68
69 pub fn set_quality(&mut self, quality: f32) {
71 self.quality = quality.clamp(0.0, 1.0);
72 }
73
74 pub fn encode_frame(&mut self, samples: &[f32], block_size: BlockSize) -> TransformFrame {
78 let frame_input = block_size.frame_input_size();
79
80 let mut channel_data: Vec<Vec<f32>> = (0..self.channels as usize)
82 .map(|_| Vec::with_capacity(samples.len() / self.channels as usize))
83 .collect();
84
85 for (i, &s) in samples.iter().enumerate() {
86 channel_data[i % self.channels as usize].push(s);
87 }
88
89 let mut all_coefficients = Vec::with_capacity(self.channels as usize);
90 let mut all_scale_factors = Vec::with_capacity(self.channels as usize);
91
92 for (ch, data) in channel_data.iter().enumerate() {
93 let mut frame_data = data.clone();
95 if frame_data.len() < frame_input {
96 frame_data.resize(frame_input, 0.0);
97 }
98
99 let coeffs = self.mdct.forward(&frame_data, block_size);
101
102 let (quantized, scale_factors) = if block_size.is_short_group() {
104 self.quantize_short_group(&coeffs, ch)
105 } else {
106 self.quantize_long_block(&coeffs, ch)
107 };
108
109 all_coefficients.push(quantized);
110 all_scale_factors.push(scale_factors);
111 }
112
113 TransformFrame {
114 coefficients: all_coefficients,
115 scale_factors: all_scale_factors,
116 block_size,
117 num_samples: block_size.frame_coefficients(),
118 }
119 }
120
121 fn quantize_long_block(&mut self, coeffs: &[f32], ch: usize) -> (Vec<i16>, Vec<f32>) {
123 let smr = self.psy_models[ch].calculate_smr(coeffs);
125
126 let bits_per_coeff = 1.0 + self.quality * 15.0;
128 let total_bits = (coeffs.len() as f32 * bits_per_coeff) as usize;
129 let allocation = self.psy_models[ch].allocate_bits(&smr, total_bits);
130
131 self.quantize_coefficients(coeffs, &smr, &allocation)
132 }
133
134 fn quantize_short_group(&mut self, coeffs: &[f32], ch: usize) -> (Vec<i16>, Vec<f32>) {
136 let coeffs_per_window = SHORT_BLOCK_SIZE / 2;
137 let bits_per_coeff = 1.0 + self.quality * 15.0;
138 let per_window_bits = (coeffs_per_window as f32 * bits_per_coeff) as usize;
139
140 let mut smr = Vec::with_capacity(coeffs.len());
141 let mut allocation = Vec::with_capacity(coeffs.len());
142 for w in 0..SHORTS_PER_GROUP {
143 let window_coeffs = &coeffs[w * coeffs_per_window..(w + 1) * coeffs_per_window];
144 let model = &mut self.short_psy_models[ch];
145 let window_smr = model.calculate_smr(window_coeffs);
146 smr.extend(window_smr.iter());
147 let window_allocation = model.allocate_bits(&window_smr, per_window_bits);
148 allocation.extend(window_allocation.iter());
149 }
150
151 let freq_resolution = self.sample_rate as f32 / SHORT_BLOCK_SIZE as f32;
152 let scale_factors = self.compute_band_scale_factors(
153 coeffs,
154 &allocation,
155 coeffs_per_window,
156 freq_resolution,
157 );
158 let smr_threshold = self.smr_threshold();
159 let quantized = self.quantize_with_scale(
160 coeffs,
161 &smr,
162 &scale_factors,
163 coeffs_per_window,
164 freq_resolution,
165 smr_threshold,
166 );
167
168 (quantized, scale_factors)
169 }
170
171 pub fn quantize_coefficients(
173 &self,
174 coeffs: &[f32],
175 smr: &[f32],
176 allocation: &[u8],
177 ) -> (Vec<i16>, Vec<f32>) {
178 let freq_resolution = self.sample_rate as f32 / LONG_BLOCK_SIZE as f32;
179 let scale_factors = self.compute_band_scale_factors(
180 coeffs,
181 allocation,
182 LONG_BLOCK_SIZE / 2,
183 freq_resolution,
184 );
185 let smr_threshold = self.smr_threshold();
186 let quantized = self.quantize_with_scale(
187 coeffs,
188 smr,
189 &scale_factors,
190 LONG_BLOCK_SIZE / 2,
191 freq_resolution,
192 smr_threshold,
193 );
194
195 (quantized, scale_factors)
196 }
197
198 fn freq_for_coeff(k: usize, coeffs_per_window: usize, freq_resolution: f32) -> f32 {
201 let bin = k % coeffs_per_window;
202 (bin as f32 + 0.5) * freq_resolution
203 }
204
205 fn compute_band_scale_factors(
208 &self,
209 coeffs: &[f32],
210 allocation: &[u8],
211 coeffs_per_window: usize,
212 freq_resolution: f32,
213 ) -> Vec<f32> {
214 let mut band_max = [0.0f32; NUM_BARK_BANDS];
216 for (k, &c) in coeffs.iter().enumerate() {
217 let freq = Self::freq_for_coeff(k, coeffs_per_window, freq_resolution);
218 let band = PsychoacousticModel::freq_to_bark_band(freq);
219 band_max[band] = band_max[band].max(c.abs());
220 }
221
222 let mut band_bits_max = [0u8; NUM_BARK_BANDS];
224 for (k, &bits) in allocation.iter().enumerate() {
225 let freq = Self::freq_for_coeff(k, coeffs_per_window, freq_resolution);
226 let band = PsychoacousticModel::freq_to_bark_band(freq);
227 band_bits_max[band] = band_bits_max[band].max(bits);
228 }
229 let max_bits = band_bits_max.iter().copied().max().unwrap_or(0);
231
232 let mut scale_factors = vec![1.0f32; NUM_BARK_BANDS];
234 for (sf, &max_val) in scale_factors.iter_mut().zip(band_max.iter()) {
235 if max_val > 1e-10 {
236 *sf = 30000.0 / max_val;
238 }
239 }
240
241 if max_bits > 0 {
243 for (sf, &bits) in scale_factors.iter_mut().zip(band_bits_max.iter()) {
244 let weight = 0.25 + 0.75 * (bits as f32 / max_bits as f32);
245 *sf *= weight;
246 }
247 }
248
249 scale_factors
250 }
251
252 fn smr_threshold(&self) -> f32 {
254 if self.quality >= 0.99 {
255 -100.0
256 } else {
257 let t = (1.0 - self.quality).max(0.001);
259 -60.0 * (1.0 - libm::powf(t, 0.5))
260 }
261 }
262
263 fn quantize_with_scale(
265 &self,
266 coeffs: &[f32],
267 smr: &[f32],
268 scale_factors: &[f32],
269 coeffs_per_window: usize,
270 freq_resolution: f32,
271 smr_threshold: f32,
272 ) -> Vec<i16> {
273 let mut quantized = vec![0i16; coeffs.len()];
274
275 for (k, (q, &c)) in quantized.iter_mut().zip(coeffs.iter()).enumerate() {
276 let freq = Self::freq_for_coeff(k, coeffs_per_window, freq_resolution);
277 let band = PsychoacousticModel::freq_to_bark_band(freq);
278
279 if smr[k] > smr_threshold {
280 let scaled = c * scale_factors[band];
282 *q = libm::roundf(scaled).clamp(I16_MIN_F32, I16_MAX_F32) as i16;
283 }
284 }
286
287 quantized
288 }
289
290 pub fn reset(&mut self) {
292 self.mdct.reset();
293 for model in &mut self.psy_models {
294 model.reset();
295 }
296 for model in &mut self.short_psy_models {
297 model.reset();
298 }
299 }
300
301 fn plan_block_types(&self, mono: &[f32], num_hops: usize) -> Vec<BlockSize> {
303 let mut plan = vec![BlockSize::Long; num_hops];
304
305 for h in 1..num_hops {
306 if self.hop_has_transient(mono, h) {
308 plan[h] = BlockSize::Short;
309 }
310 }
311
312 let mut h = 0;
314 while h < num_hops {
315 if plan[h] == BlockSize::Short {
316 let mut run_end = h;
317 while run_end + 1 < num_hops && plan[run_end + 1] == BlockSize::Short {
318 run_end += 1;
319 }
320 if h > 0 {
323 plan[h - 1] = BlockSize::Start;
324 plan[run_end] = BlockSize::Stop;
325 }
326 h = run_end + 1;
327 } else {
328 h += 1;
329 }
330 }
331
332 plan
333 }
334
335 fn hop_has_transient(&self, mono: &[f32], h: usize) -> bool {
337 let grid_start = h * HOP_SIZE;
338
339 let mut window_energy = [0.0f32; SHORTS_PER_GROUP];
341 for w in 0..SHORTS_PER_GROUP {
342 let off = grid_start + SHORT_GROUP_OFFSET + w * (SHORT_BLOCK_SIZE / 2);
343 let mut sum = 0.0f32;
344 for i in 0..SHORT_BLOCK_SIZE {
345 let v = mono[off + i];
346 sum += v * v;
347 }
348 window_energy[w] = sum / SHORT_BLOCK_SIZE as f32;
349 }
350
351 let mut grid_sum = 0.0f32;
353 for i in 0..LONG_BLOCK_SIZE {
354 let v = mono[grid_start + i];
355 grid_sum += v * v;
356 }
357 let floor = grid_sum / LONG_BLOCK_SIZE as f32 * DETECTOR_FLOOR_FRACTION;
358
359 for w in 0..SHORTS_PER_GROUP {
361 let baseline = window_energy[w.saturating_sub(1)].max(floor);
362 if window_energy[w] > ATTACK_RATIO * baseline {
363 return true;
364 }
365 }
366
367 false
368 }
369
370 pub fn encode_to_flo(&mut self, samples: &[f32], metadata: &[u8]) -> crate::FloResult<Vec<u8>> {
374 let block_samples = LONG_BLOCK_SIZE;
375 let hop_size = HOP_SIZE;
376
377 let num_samples_per_channel = samples.len() / self.channels as usize;
381
382 let pre_roll = hop_size;
384 let total_samples = num_samples_per_channel + pre_roll;
385 let num_hops = total_samples.div_ceil(hop_size);
386 let total_samples_needed = (num_hops + 1) * hop_size;
387
388 let mut padded = vec![0.0f32; total_samples_needed * self.channels as usize];
390
391 for ch in 0..self.channels as usize {
393 for i in 0..num_samples_per_channel.min(total_samples_needed - pre_roll) {
394 let src_idx = i * self.channels as usize + ch;
395 let dst_idx = (i + pre_roll) * self.channels as usize + ch;
396 if src_idx < samples.len() && dst_idx < padded.len() {
397 padded[dst_idx] = samples[src_idx];
398 }
399 }
400 }
401
402 let mono: Vec<f32> = (0..total_samples_needed)
404 .map(|i| {
405 let mut sum = 0.0f32;
406 for ch in 0..self.channels as usize {
407 sum += padded[i * self.channels as usize + ch];
408 }
409 sum / self.channels as f32
410 })
411 .collect();
412
413 let plan = self.plan_block_types(&mono, num_hops);
415
416 let mut encoded_frames: Vec<Frame> = Vec::new();
418
419 for hop_idx in 0..num_hops {
421 let start = hop_idx * hop_size * self.channels as usize;
422 let end = start + block_samples * self.channels as usize;
423
424 if end > padded.len() {
425 break;
426 }
427
428 let frame_samples = &padded[start..end];
429 let transform_frame = self.encode_frame(frame_samples, plan[hop_idx]);
430
431 let frame_data = serialize_frame(&transform_frame);
433
434 let mut flo_frame = Frame::new(FrameType::Transform as u8, hop_size as u32);
436 flo_frame.channels.push(ChannelData {
437 predictor_coeffs: vec![],
438 shift_bits: 0,
439 residual_encoding: ResidualEncoding::Raw,
440 rice_parameter: 0,
441 residuals: frame_data,
442 });
443
444 encoded_frames.push(flo_frame);
445 }
446
447 let writer = crate::Writer::new();
449 writer.write_ex(
450 self.sample_rate,
451 self.channels,
452 16, 5, true, (libm::roundf(self.quality * 4.0) as u8).min(4), &encoded_frames,
457 metadata,
458 )
459 }
460}
461
462pub fn serialize_frame(frame: &TransformFrame) -> Vec<u8> {
464 let mut data = Vec::new();
465
466 data.push(match frame.block_size {
468 BlockSize::Long => 0,
469 BlockSize::Short => 1,
470 BlockSize::Start => 2,
471 BlockSize::Stop => 3,
472 });
473
474 data.push(frame.coefficients.len() as u8);
476
477 for sf in &frame.scale_factors {
480 for &s in sf {
481 let log_sf = if s > 1e-10 {
483 ((libm::log2f(s) * 256.0) + 32768.0).clamp(0.0, 65535.0) as u16
484 } else {
485 0
486 };
487 data.extend_from_slice(&log_sf.to_le_bytes());
488 }
489 }
490
491 for quantized in &frame.coefficients {
493 let encoded = serialize_sparse(quantized);
494 let len = encoded.len() as u32;
495 data.extend_from_slice(&len.to_le_bytes());
496 data.extend_from_slice(&encoded);
497 }
498
499 data
500}
501
502pub fn serialize_sparse(coeffs: &[i16]) -> Vec<u8> {
505 let mut output = Vec::new();
506 let mut i = 0;
507
508 while i < coeffs.len() {
509 let zero_start = i;
511 while i < coeffs.len() && coeffs[i] == 0 {
512 i += 1;
513 }
514 let zero_count = i - zero_start;
515
516 let non_zero_start = i;
518 while i < coeffs.len() && coeffs[i] != 0 && (i - non_zero_start) < 255 {
519 i += 1;
520 }
521 let non_zero_count = i - non_zero_start;
522
523 encode_varint(&mut output, zero_count as u32);
525 output.push(non_zero_count as u8);
526
527 for j in non_zero_start..non_zero_start + non_zero_count {
529 output.extend_from_slice(&coeffs[j].to_le_bytes());
530 }
531 }
532
533 output
534}
535
536fn encode_varint(output: &mut Vec<u8>, mut value: u32) {
538 loop {
539 let mut byte = (value & 0x7F) as u8;
540 value >>= 7;
541 if value != 0 {
542 byte |= 0x80;
543 }
544 output.push(byte);
545 if value == 0 {
546 break;
547 }
548 }
549}