lc3_codec/encoder/
bandwidth_detector.rs

1use crate::common::{complex::Scaler, config::FrameDuration};
2
3// checked against spec
4
5const I_BW_START_TABLE: [[usize; 4]; 4] = [[53, 0, 0, 0], [47, 59, 0, 0], [44, 54, 60, 0], [41, 51, 57, 61]];
6const I_BW_STOP_TABLE: [[usize; 4]; 4] = [[63, 0, 0, 0], [56, 63, 0, 0], [52, 59, 63, 0], [49, 55, 60, 63]];
7const I_BW_START_TABLE_7P5MS: [[usize; 4]; 4] = [[51, 0, 0, 0], [45, 58, 0, 0], [42, 53, 60, 0], [40, 51, 57, 61]];
8const I_BW_STOP_TABLE_7P5MS: [[usize; 4]; 4] = [[63, 0, 0, 0], [55, 63, 0, 0], [51, 58, 63, 0], [48, 55, 60, 63]];
9const NBITS_BW_TABLE: [usize; 5] = [0, 1, 2, 2, 3];
10
11// quietness thresholds (TQ) for each bandwidth index
12const QUIETNESS_THRESH: [usize; 4] = [20, 10, 10, 10];
13
14// cutoff throsholds (TC) for each bandwidth index
15const CUTOFF_THRESH: [usize; 4] = [15, 23, 20, 20];
16
17const L_10MS: [usize; 4] = [4, 4, 3, 1];
18const L_7P5MS: [usize; 4] = [4, 4, 3, 2];
19
20pub struct BandwidthDetector {
21    sample_freq_ind: usize, // n_bw
22    i_bw_start: &'static [usize],
23    i_bw_stop: &'static [usize],
24    l: &'static [usize],
25}
26
27pub struct BandwidthDetectorResult {
28    pub bandwidth_ind: usize,
29    pub nbits_bandwidth: usize,
30}
31
32impl BandwidthDetector {
33    pub fn new(frame_duration: FrameDuration, sample_freq_ind: usize) -> Self {
34        let (i_bw_start, i_bw_stop, l) = match frame_duration {
35            FrameDuration::TenMs => (
36                I_BW_START_TABLE[sample_freq_ind - 1].as_slice(),
37                I_BW_STOP_TABLE[sample_freq_ind - 1].as_slice(),
38                L_10MS.as_slice(),
39            ),
40            FrameDuration::SevenPointFiveMs => (
41                I_BW_START_TABLE_7P5MS[sample_freq_ind - 1].as_slice(),
42                I_BW_STOP_TABLE_7P5MS[sample_freq_ind - 1].as_slice(),
43                L_7P5MS.as_slice(),
44            ),
45        };
46
47        Self {
48            sample_freq_ind,
49            i_bw_start,
50            i_bw_stop,
51            l,
52        }
53    }
54
55    pub fn get_num_bits_bandwidth(&self) -> usize {
56        NBITS_BW_TABLE[self.sample_freq_ind]
57    }
58
59    /// Detect bandlimited signals coded at higher sampling rates (upsampled signals)
60    ///
61    /// # Arguments
62    ///
63    /// * `e_b` - Input
64    pub fn run(&self, e_b: &[Scaler]) -> BandwidthDetectorResult {
65        let nbits_bandwidth = NBITS_BW_TABLE[self.sample_freq_ind];
66        if self.sample_freq_ind == 0 {
67            return BandwidthDetectorResult {
68                bandwidth_ind: 0,
69                nbits_bandwidth,
70            };
71        }
72
73        // bandwidth index candidate
74        let mut bandwidth_ind = 0;
75
76        // first stage - find the highest non-quiet band
77        // start with the highest bandwidth and work down until a non-quiet band is detected
78        for k in (0..self.sample_freq_ind).rev() {
79            let start = self.i_bw_start[k];
80            let stop = self.i_bw_stop[k];
81            let width = (stop + 1 - start) as Scaler;
82            let mut quietness = 0.0;
83
84            // calculate the quietness of the energy band
85            for energy in e_b[start..=stop].iter() {
86                quietness += *energy / width;
87            }
88
89            // if this quiteness is over the threshold then then this is the candidate bandwidth for this band
90            if quietness >= QUIETNESS_THRESH[k] as Scaler {
91                bandwidth_ind = k + 1;
92                break;
93            }
94        }
95
96        // second stage - determine the final bandwidth
97        if self.sample_freq_ind == bandwidth_ind {
98            BandwidthDetectorResult {
99                bandwidth_ind,
100                nbits_bandwidth,
101            }
102        } else {
103            // detect an energy drop above the cut-off frequency of the candidate bandwidth bw_0
104            let mut cutoff_max = 0.0;
105            let l_bw = self.l[bandwidth_ind];
106            let from = self.i_bw_start[bandwidth_ind] + 1 - l_bw;
107            let to = self.i_bw_start[bandwidth_ind];
108            for n in from..to {
109                // NOTE: the spec calls for adding EPSILON and multiplying this by 10log10
110                // which does not seem to have any effect
111                let cutoff = e_b[n - l_bw] / e_b[n];
112                cutoff_max = cutoff.max(cutoff_max);
113            }
114
115            if cutoff_max > CUTOFF_THRESH[bandwidth_ind] as Scaler {
116                BandwidthDetectorResult {
117                    bandwidth_ind,
118                    nbits_bandwidth,
119                }
120            } else {
121                BandwidthDetectorResult {
122                    bandwidth_ind: self.sample_freq_ind,
123                    nbits_bandwidth,
124                }
125            }
126        }
127    }
128}
129
130#[cfg(test)]
131mod tests {
132    extern crate std;
133    use super::*;
134    use crate::common::config::{FrameDuration, Lc3Config, SamplingFrequency};
135
136    #[test]
137    fn bandwidth_detector_run() {
138        let config = Lc3Config::new(SamplingFrequency::Hz48000, FrameDuration::TenMs);
139        let detector = BandwidthDetector::new(config.n_ms, config.fs_ind);
140        #[rustfmt::skip]
141        let e_b = [
142            18782358.0, 38743940.0, 616163.4, 395644.22, 20441758.0, 31336932.0, 130985740.0, 116001040.0, 297851520.0,
143            52884070.0, 13922108.0, 1211718.9, 643103.44, 2697760.3, 1674064.1, 8157596.5, 11880675.0, 615179.8,
144            1548138.0, 15001.449, 72356.61, 424075.13, 339332.63, 9093.422, 118530.22, 106300.99, 93872.414, 103234.38,
145            129645.81, 12188.947, 48738.766, 124244.47, 12835.649, 47138.63, 10050.675, 24161.475, 15844.599, 16136.73,
146            37085.188, 5236.445, 14986.677, 10497.837, 8121.843, 2109.306, 3711.1233, 3116.423, 3749.5027, 4903.189,
147            3149.5522, 1745.0712, 1382.3269, 1555.3384, 994.6934, 1484.393, 888.5528, 926.9374, 639.82434, 801.4557,
148            743.6313, 487.39868, 681.486, 519.567, 481.0444, 454.6319,
149        ];
150
151        let result = detector.run(&e_b);
152
153        assert_eq!(result.bandwidth_ind, 4);
154        assert_eq!(result.nbits_bandwidth, 3);
155    }
156}