libflo_audio/lossy/
mod.rs

1//! Transform-based lossy encoder for flo™
2//!
3//! Combines MDCT, psychoacoustic model, quantization, and entropy coding
4//! for high-quality lossy compression comparable to MP3/AAC/Vorbis.
5
6pub mod decoder;
7pub mod encoder;
8pub mod mdct;
9pub mod psychoacoustic;
10
11// Re-export main types
12pub use decoder::{deserialize_frame, deserialize_sparse, TransformDecoder};
13pub use encoder::{serialize_frame, serialize_sparse, TransformEncoder, TransformFrame};
14pub use mdct::{BlockSize, Mdct, WindowType};
15pub use psychoacoustic::{PsychoacousticModel, BARK_BAND_EDGES, NUM_BARK_BANDS};
16
17/// Quality presets for lossy encoding
18#[derive(Debug, Clone, Copy, PartialEq)]
19pub enum QualityPreset {
20    /// Lowest quality, highest compression (~30:1)
21    /// Good for speech, podcasts, low bandwidth
22    Low,
23    /// Medium quality, good compression (~10:1)
24    /// Good for general music
25    Medium,
26    /// High quality, moderate compression (~6:1)
27    /// Good for quality-conscious listening
28    High,
29    /// Very high quality, light compression (~4:1)
30    /// Near-transparent for most content
31    VeryHigh,
32    /// Transparent quality, minimal loss (~3:1)
33    /// Perceptually lossless for almost all content
34    Transparent,
35}
36
37impl QualityPreset {
38    /// Get the numeric quality value (0.0-1.0)
39    pub fn as_f32(self) -> f32 {
40        match self {
41            QualityPreset::Low => 0.0,
42            QualityPreset::Medium => 0.35,
43            QualityPreset::High => 0.55,
44            QualityPreset::VeryHigh => 0.75,
45            QualityPreset::Transparent => 1.0,
46        }
47    }
48
49    /// Create from numeric value
50    pub fn from_f32(quality: f32) -> Self {
51        if quality < 0.2 {
52            QualityPreset::Low
53        } else if quality < 0.45 {
54            QualityPreset::Medium
55        } else if quality < 0.65 {
56            QualityPreset::High
57        } else if quality < 0.85 {
58            QualityPreset::VeryHigh
59        } else {
60            QualityPreset::Transparent
61        }
62    }
63
64    /// Estimate compression ratio for this quality level
65    pub fn expected_ratio(self) -> f32 {
66        match self {
67            QualityPreset::Low => 30.0,
68            QualityPreset::Medium => 10.0,
69            QualityPreset::High => 6.0,
70            QualityPreset::VeryHigh => 4.0,
71            QualityPreset::Transparent => 3.0,
72        }
73    }
74
75    /// Estimate equivalent bitrate (kbps) for stereo 44.1kHz
76    pub fn equivalent_bitrate(self) -> u32 {
77        match self {
78            QualityPreset::Low => 48,
79            QualityPreset::Medium => 128,
80            QualityPreset::High => 192,
81            QualityPreset::VeryHigh => 256,
82            QualityPreset::Transparent => 320,
83        }
84    }
85
86    /// Create quality preset from target bitrate
87    pub fn from_bitrate(bitrate_kbps: u32, sample_rate: u32, channels: u8) -> Self {
88        // Calculate raw PCM bitrate
89        let raw_kbps = (sample_rate as u64 * channels as u64 * 16) / 1000;
90        let target_ratio = raw_kbps as f32 / bitrate_kbps as f32;
91
92        if target_ratio > 20.0 {
93            QualityPreset::Low
94        } else if target_ratio > 10.0 {
95            QualityPreset::Medium
96        } else if target_ratio > 6.0 {
97            QualityPreset::High
98        } else if target_ratio > 4.0 {
99            QualityPreset::VeryHigh
100        } else {
101            QualityPreset::Transparent
102        }
103    }
104}
105
106impl From<u8> for QualityPreset {
107    fn from(v: u8) -> Self {
108        match v {
109            0 => QualityPreset::Low,
110            1 => QualityPreset::Medium,
111            2 => QualityPreset::High,
112            3 => QualityPreset::VeryHigh,
113            _ => QualityPreset::Transparent,
114        }
115    }
116}
117
118impl From<QualityPreset> for u8 {
119    fn from(q: QualityPreset) -> u8 {
120        match q {
121            QualityPreset::Low => 0,
122            QualityPreset::Medium => 1,
123            QualityPreset::High => 2,
124            QualityPreset::VeryHigh => 3,
125            QualityPreset::Transparent => 4,
126        }
127    }
128}