use crate::{ common::{ complex::{Complex, Scaler}, config::{FrameDuration, Lc3Config}, dct_iv::DiscreteCosTransformIv, }, tables::mdct_windows::*, }; #[allow(unused_imports)] use num_traits::real::Real; /// Modified Discrete Cosine Transform pub struct ModDiscreteCosTrans<'a> { config: Lc3Config, dct_iv: DiscreteCosTransformIv<'a>, mem_ola_add: &'a mut [Scaler], t_hat_mdct: &'a mut [Scaler], wn: &'static [Scaler], zeros: &'a [Scaler], half_nf_scratch: &'a mut [Scaler], } impl<'a> ModDiscreteCosTrans<'a> { pub fn new( config: Lc3Config, scaler_buf: &'a mut [Scaler], complex_buf: &'a mut [Complex], ) -> (Self, &'a mut [Scaler], &'a mut [Complex]) { let (dctiv_dbl, complex_buf) = DiscreteCosTransformIv::new(config.nf, complex_buf); let (mem_ola_add, scaler_buf) = scaler_buf.split_at_mut(config.nf - config.z); let (t_hat_mdct, scaler_buf) = scaler_buf.split_at_mut(config.nf * 2); let (zeros, scaler_buf) = scaler_buf.split_at_mut(config.nf - config.ne); zeros.fill(0.0); let (half_nf_scratch, scaler_buf) = scaler_buf.split_at_mut(config.nf / 2); let wn: &'static [Scaler] = match config.n_ms { FrameDuration::SevenPointFiveMs => match config.nf { 60 => &W_N60_7P5MS, 120 => &W_N120_7P5MS, 180 => &W_N180_7P5MS, 240 => &W_N240_7P5MS, 360 => &W_N360_7P5MS, _ => panic!("Cannot lookup wn for 7.5ms, invalid nf: {}", config.nf), }, FrameDuration::TenMs => match config.nf { 80 => &W_N80_10MS, 160 => &W_N160_10MS, 240 => &W_N240_10MS, 320 => &W_N320_10MS, 480 => &W_N480_10MS, _ => panic!("Cannot lookup wn for 10ms, invalid nf: {}", config.nf), }, }; ( Self { config, dct_iv: dctiv_dbl, mem_ola_add, t_hat_mdct, wn, zeros, half_nf_scratch, }, scaler_buf, complex_buf, ) } /// Split input spectral lines into slices according to frequency bands associated with the frame duration and bandwidth /// /// # Arguments /// /// * `spec_lines` - Input spectral lines (e.g. 400 entries) /// * `freq_samples` - Output frequency samples (e.g. 480 entries) pub fn run(&mut self, spec_lines: &[Scaler], freq_samples: &mut [Scaler]) { assert_eq!(spec_lines.len(), self.config.ne); assert_eq!(freq_samples.len(), self.config.nf); // copy spectral lines to the output buffer for in-place processing and pad the remaining entries with zero freq_samples[..self.config.ne].copy_from_slice(spec_lines); freq_samples[self.config.ne..].copy_from_slice(self.zeros); // 1. generation of the time domain aliasing buffer self.apply_mdct_inverse(freq_samples); // 2. windowing of the time-aliased buffer - read wn in reverse order // it is assumed that t_hat_mdct and wn are nf * 2 in length for (t_hat, wn) in self.t_hat_mdct.iter_mut().zip(self.wn.iter().rev()) { *t_hat *= *wn; } // 3. conduct overlap-add operation to get reconstructed time samples self.overlap_add(freq_samples); } fn apply_mdct_inverse(&mut self, buf: &mut [Scaler]) { self.dct_iv.run(buf); let nf = self.config.nf; assert_eq!(buf.len(), nf); self.t_hat_mdct[..nf].copy_from_slice(buf); for (to, from) in self.t_hat_mdct[nf..(nf * 2)].iter_mut().zip(buf.iter().rev()) { *to = -*from; } let half_nf = nf / 2; self.half_nf_scratch.copy_from_slice(&self.t_hat_mdct[..half_nf]); // move chunks of data half nf to the left (not sure if this is the best way to do this) { let (left, right) = self.t_hat_mdct.split_at_mut(half_nf); left.copy_from_slice(&right[..half_nf]); } { let (left, right) = self.t_hat_mdct[half_nf..].split_at_mut(half_nf); left.copy_from_slice(&right[..half_nf]); } { let (left, right) = self.t_hat_mdct[nf..].split_at_mut(half_nf); left.copy_from_slice(&right[..half_nf]); } for (to, from) in self.t_hat_mdct[(half_nf * 3)..] .iter_mut() .zip(self.half_nf_scratch.iter()) { *to = -*from; } let gain = 1. / (2. * nf as Scaler).sqrt(); for item in self.t_hat_mdct.iter_mut().take(2 * nf) { *item *= gain; } } fn overlap_add(&mut self, freq_buf: &mut [Scaler]) { let nf = self.config.nf; let z = self.config.z; for (freq_buf_n, (mem_ola_add_n, t_hat_mdct_z)) in freq_buf[..(nf - z)] .iter_mut() .zip(self.mem_ola_add[..(nf - z)].iter().zip(self.t_hat_mdct[z..nf].iter())) { *freq_buf_n = *mem_ola_add_n + *t_hat_mdct_z; } self.mem_ola_add[..(nf - z)].copy_from_slice(&self.t_hat_mdct[(nf + z)..(nf * 2)]); freq_buf[(nf - z)..nf].copy_from_slice(&self.t_hat_mdct[nf..(nf + z)]); } pub const fn calc_working_buffer_length(config: &Lc3Config) -> (usize, usize) { let dct_complex_length = DiscreteCosTransformIv::calc_working_buffer_length(config); let mem_ola_add_length = config.nf - config.z; let t_hat_mdct_length = config.nf * 2; let zeros_length = config.nf - config.ne; let half_nf_length = config.nf / 2; let x_hat_mdct_length = config.nf; ( half_nf_length + zeros_length + mem_ola_add_length + t_hat_mdct_length + x_hat_mdct_length, dct_complex_length, ) } } #[cfg(test)] mod tests { extern crate std; use super::*; use crate::common::config::{FrameDuration, SamplingFrequency}; #[test] fn modified_dct_decode() { const CONFIG: Lc3Config = Lc3Config::new(SamplingFrequency::Hz48000, FrameDuration::TenMs); const SCALER_COMPLEX_LENS: (usize, usize) = ModDiscreteCosTrans::calc_working_buffer_length(&CONFIG); let mut scaler_buf = [0f32; SCALER_COMPLEX_LENS.0]; let mut complex_buf = [Complex { r: 0., i: 0. }; SCALER_COMPLEX_LENS.1]; let (mut mdct, _, _) = ModDiscreteCosTrans::new(CONFIG, &mut scaler_buf, &mut complex_buf); let mut freq_buf = [0.0; CONFIG.nf]; // since the modified dct result is based on some data from the previous frame we need to plocess two frames in our test #[rustfmt::skip] let x_hat = [ -1293.1299, 245.53099, 5084.983, -5084.029, 161.85847, -1601.2933, 2313.1963, 5822.268, -15994.899, 6625.739, 15630.219, 8686.201, -275.8873, -472.84, -249.1974, 1216.9434, 1066.6044, 0.0, -320.7793, -520.7456, 1869.116, -568.8614, -654.3916, 548.98627, -1249.3191, 239.03938, -898.2346, 425.92346, -621.90796, -880.73676, 384.04172, 0.0, -305.9874, -54.920815, -367.12482, 170.01082, 589.13873, -465.65112, 95.18835, -572.1217, 249.79962, -185.33519, 58.88405, -89.72807, 44.864037, -128.30061, 85.53374, -42.76687, -483.6944, 148.82904, -37.20726, 32.418316, -259.34653, -64.83663, 226.9282, 56.562077, -56.562077, -141.40518, -28.281038, 76.8806, -281.8955, -128.13432, 102.50746, -48.093624, 96.18725, 96.18725, 96.18725, -180.40393, 0.0, -157.85344, 0.0, 21.137903, 63.41371, 126.82742, 21.137903, 0.0, 118.98418, 39.661392, 0.0, -118.98418, -337.12183, 37.249435, 0.0, 148.99774, -111.74831, 55.874153, -34.993866, -52.490803, 34.993866, -34.993866, -34.993866, 0.0, 32.8947, 32.8947, -49.34205, -16.44735, -32.8947, -16.44735, -77.540886, -15.508177, -15.508177, 108.557236, 0.0, -46.52453, 15.508177, 0.0, 29.343197, -29.343197, 44.014793, 0.0, 0.0, -14.671598, 13.829894, 55.319576, 0.0, -27.659788, -13.829894, 13.829894, 0.0, 26.142889, 0.0, 52.285778, -39.214333, 39.214333, 26.142889, 65.35722, -26.142889, 0.0, 0.0, -25.882666, 51.76533, -25.882666, 51.76533, -12.941333, 51.76533, 0.0, 40.274414, 40.274414, -40.274414, 0.0, 40.274414, -26.84961, 40.274414, -13.424805, -13.92249, 27.84498, 0.0, 13.92249, -27.84498, -13.92249, -41.76747, -13.92249, 0.0, 0.0, -72.17195, -28.86878, -14.43439, 0.0, 0.0, 28.86878, 14.43439, 14.43439, 28.86878, 14.43439, 13.464998, 13.464998, -13.464998, 0.0, 0.0, 0.0, -13.464998, -13.464998, 0.0, -26.929996, 26.929996, 11.253014, 11.253014, 0.0, -11.253014, 22.506027, 0.0, -11.253014, -11.253014, 0.0, 0.0, 11.253014, 9.373507, -18.747013, 9.373507, -9.373507, 0.0, -28.12052, -37.494026, 0.0, 0.0, -18.747013, -28.12052, -9.373507, 0.0, 0.0, 0.0, 0.0, 0.0, 7.8264794, -7.8264794, 23.479439, 15.652959, -7.8264794, 7.8264794, 7.8264794, 0.0, 0.0, 0.0, 0.0, 19.732956, 0.0, 6.577652, 0.0, 13.155304, -19.732956, 6.577652, 6.577652, 19.732956, 0.0, -13.155304, -5.5446987, 0.0, 0.0, 0.0, -11.089397, -5.5446987, 0.0, 0.0, 0.0, 0.0, 11.089397, 0.0, 5.5446987, 0.0, 5.5446987, -4.661485, -4.661485, 0.0, 0.0, -4.661485, 0.0, 0.0, 4.661485, -9.32297, 4.661485, -4.661485, -4.661485, -4.661485, -9.32297, 0.0, 4.661485, 0.0, -3.9280114, 3.9280114, 0.0, 3.9280114, -11.784035, 3.9280114, 3.9280114, 0.0, 0.0, -3.9280114, 0.0, -3.9280114, 3.9280114, 0.0, -3.9280114, -3.9280114, 3.5038724, -3.5038724, 7.007745, 0.0, 0.0, -7.007745, 10.511617, 0.0, 0.0, 3.5038724, 0.0, 0.0, 0.0, -3.5038724, 7.007745, 0.0, -3.5038724, 3.5038724, 0.0, 0.0, -3.3093805, -3.3093805, 0.0, 0.0, 3.3093805, 3.3093805, 0.0, -3.3093805, -6.618761, 3.3093805, -3.3093805, -3.3093805, 0.0, 3.3093805, 0.0, -6.618761, 6.618761, 0.0, 0.0, 0.0, 0.39045277, -0.39045277, 0.39045277, -0.39045277, 0.39045277, 0.39045277, -0.39045277, -0.39045277, 0.39045277, 0.39045277, -0.39045277, -0.39045277, 0.39045277, 0.39045277, -0.39045277, -0.39045277, -0.39045277, -0.36832458, 0.36832458, -0.36832458, -0.36832458, -0.36832458, 0.36832458, 0.36832458, -0.36832458, -0.36832458, -0.36832458, -0.36832458, 0.36832458, -0.36832458, 0.36832458, -0.36832458, 0.36832458, -0.36832458, 0.36832458, -0.36832458, 0.36832458, 0.36832458, -0.36832458, 0.347288, 0.347288, 0.347288, -0.347288, 0.347288, 0.347288, -0.347288, 0.347288, -0.347288, 0.347288, -0.347288, -0.347288, 0.347288, -0.347288, 0.347288, 0.347288, -0.347288, 0.347288, -0.347288, -0.347288, -0.347288, 0.347288, -0.347288, -0.32734314, -0.32734314, -0.32734314, -0.32734314, -0.32734314, -0.32734314, 0.32734314, -0.32734314, 0.32734314, -0.32734314, 0.32734314, -0.32734314, -0.32734314, -0.32734314, 0.32734314, -0.32734314, 0.32734314, -0.32734314, -0.32734314, -0.32734314, -0.32734314, 0.32734314, -0.32734314, -0.32734314, -0.32734314, ]; mdct.run(&x_hat, &mut freq_buf); #[rustfmt::skip] let x_hat = [ -1206.3026, -5241.9336, -155.86848, -6830.6084, -1300.3838, -3559.517, 710.1283, 3473.764, -9982.126, 13719.041, 16283.188, 11467.5205, 6554.3584, -908.4256, 1152.2314, 1950.774, 2570.5566, 3246.4722, 1030.247, -679.5246, 1077.3108, 902.3161, -610.1385, 1887.744, 482.0292, 334.6572, 176.37881, 299.07712, -373.0097, 239.96167, -435.3793, -223.21477, 26.76417, 158.52623, 315.89703, 239.31595, 123.17562, 180.30057, -180.30057, 48.224026, 114.73992, 354.19717, -24.764124, 123.82062, -74.29237, 48.767937, -243.83968, -268.22363, 203.26685, 76.22507, 406.5337, 0.0, -158.81937, 52.939785, -79.40968, 55.13717, 82.70576, 0.0, 82.70576, -84.65056, 84.65056, 253.95168, -225.73482, 28.387463, -283.87463, 28.387463, 170.32478, -228.47122, -171.35342, -57.117805, 28.558903, -86.19353, 28.731174, -57.46235, 57.46235, -114.9247, 26.455284, -185.187, 158.73172, -158.73172, 26.455284, -66.682495, -44.454994, -66.682495, 22.227497, -22.227497, -18.662209, 0.0, 111.97325, -55.986626, 130.63545, 0.0, -62.814857, 31.407429, 31.407429, 62.814857, -15.703714, 62.814857, -14.205091, 0.0, -56.820366, -28.410183, -113.64073, -14.205091, -28.410183, -13.7488165, -41.246452, -41.246452, 54.995266, 13.7488165, 0.0, 13.7488165, 39.913975, 53.21863, 0.0, -66.523285, 13.304658, -66.523285, 0.0, -38.61785, 25.745234, 12.872617, 0.0, -38.61785, 77.2357, -25.745234, 12.872617, -37.42575, 24.9505, -24.9505, -37.42575, 0.0, 37.42575, -24.9505, -12.47525, 24.22137, -12.110685, 12.110685, -12.110685, 0.0, -12.110685, 0.0, 0.0, 12.110685, 0.0, 35.26723, -11.755743, 11.755743, 11.755743, 0.0, -11.755743, -23.511486, 23.511486, -11.755743, 45.64168, 11.41042, 45.64168, 0.0, -22.82084, -34.231262, 0.0, 0.0, -11.41042, 0.0, -21.812521, 0.0, 21.812521, -21.812521, -21.812521, -10.9062605, 10.9062605, -10.9062605, 10.9062605, 0.0, 21.812521, -30.796978, 41.062637, 10.265659, -10.265659, -20.531319, -20.531319, -20.531319, 30.796978, 10.265659, -30.796978, 30.796978, 0.0, 0.0, -19.329084, 0.0, -9.664542, -19.329084, -9.664542, 19.329084, -9.664542, -9.664542, 9.664542, -19.329084, -9.102908, 9.102908, 0.0, 0.0, -9.102908, 0.0, -18.205816, -9.102908, 0.0, 18.205816, 0.0, -27.308725, 9.102908, 0.0, -8.259274, -16.518547, 8.259274, 16.518547, 0.0, 16.518547, 0.0, -8.259274, 8.259274, -8.259274, 0.0, 0.0, -8.259274, 7.201717, 0.0, 0.0, 0.0, -14.403434, 14.403434, 21.605152, 0.0, -7.201717, -7.201717, 0.0, 14.403434, 0.0, 0.0, 0.0, 0.0, 6.2782655, 6.2782655, 0.0, 0.0, 6.2782655, -18.834797, 0.0, 0.0, 0.0, 6.2782655, 0.0, -6.2782655, -6.2782655, 6.2782655, 6.2782655, 0.0, 0.0, 0.0, -5.460496, 5.460496, -5.460496, 0.0, 0.0, 0.0, 0.0, 0.0, -5.460496, 5.460496, 5.460496, 5.460496, 0.0, 10.920992, 0.0, 4.7637267, 0.0, 0.0, 0.0, 14.29118, 4.7637267, -4.7637267, -9.527453, -4.7637267, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 4.7637267, -4.7637267, 0.0, 4.180775, 0.0, 0.0, 4.180775, 0.0, 0.0, 0.0, 0.5225969, -0.5225969, -0.5225969, 0.0, 0.0, 0.0, -4.180775, 0.0, 0.0, 0.0, 0.0, 3.6689022, 0.0, 0.0, 0.0, -0.45861277, 0.45861277, -0.45861277, 0.45861277, -0.45861277, 0.45861277, -0.45861277, 0.45861277, 0.45861277, -0.45861277, 0.45861277, 0.45861277, -0.45861277, -0.45861277, -0.45861277, 0.45861277, -0.40255708, 0.40255708, 0.40255708, 0.40255708, 0.40255708, 0.40255708, -0.40255708, -0.40255708, 0.40255708, -0.40255708, -0.40255708, -0.40255708, -0.40255708, 0.40255708, -0.40255708, 0.40255708, -0.40255708, -0.40255708, -0.40255708, -0.40255708, -0.40255708, -0.40255708, 0.35250783, 0.35250783, 0.35250783, -0.35250783, -0.35250783, -0.35250783, 0.35250783, -0.35250783, -0.35250783, 0.35250783, -0.35250783, 0.35250783, -0.35250783, -0.35250783, -0.35250783, -0.35250783, -0.35250783, 0.35250783, 0.35250783, -0.35250783, -0.35250783, 0.35250783, -0.35250783, -0.30846497, -0.30846497, 0.30846497, 0.30846497, 0.30846497, -0.30846497, 0.30846497, 0.30846497, 0.30846497, 0.30846497, -0.30846497, -0.30846497, 0.30846497, 0.30846497, -0.30846497, -0.30846497, 0.30846497, -0.30846497, -0.30846497, -0.30846497, -0.30846497, 0.30846497, 0.30846497, 0.30846497, -0.30846497, ]; mdct.run(&x_hat, &mut freq_buf); #[rustfmt::skip] let freq_buf_expected = [ 329.20435, 408.6457, 478.11908, 539.0993, 594.16406, 648.3305, 708.14233, 785.74414, 890.35443, 999.2488, 1079.0262, 1132.4252, 1189.0614, 1263.9072, 1339.4902, 1392.2119, 1417.1182, 1425.354, 1435.8098, 1460.9797, 1491.7046, 1497.5272, 1465.1193, 1420.476, 1384.7596, 1346.7651, 1290.0562, 1215.2373, 1128.5273, 1029.5582, 915.7318, 790.9405, 676.49603, 585.3717, 487.85953, 352.15723, 193.05173, 43.70752, -79.54181, -179.14104, -281.92233, -413.2743, -559.9556, -692.07996, -803.9083, -909.9745, -1006.51044, -1082.2643, -1151.0464, -1224.5739, -1292.6034, -1336.433, -1347.5631, -1328.6221, -1280.745, -1216.1796, -1151.6594, -1093.9952, -1048.0684, -1017.9504, -1002.10223, -981.77826, -941.59033, -890.55035, -838.1291, -788.71924, -745.4917, -699.9309, -636.0759, -554.6262, -479.2781, -425.42758, -386.08118, -344.19168, -287.30737, -217.94397, -140.66211, -46.776215, 76.1028, 217.96478, 339.66168, 412.4326, 450.45532, 480.96487, 510.65192, 541.6527, 586.5333, 656.83167, 752.2529, 860.5596, 959.82214, 1028.0052, 1065.2461, 1087.8615, 1102.1747, 1105.4282, 1092.1143, 1056.633, 1004.8624, 952.7927, 911.83606, 885.2831, 866.05597, 835.6201, 786.88513, 736.35693, 700.3611, 670.18115, 619.1756, 535.6963, 431.58707, 319.88318, 203.31271, 78.91724, -53.230103, -184.99063, -304.14954, -404.76013, -498.30124, -603.3264, -718.1176, -831.5375, -946.0727, -1062.2368, -1171.7661, -1261.2023, -1324.2283, -1379.13, -1441.5575, -1501.7023, -1546.9458, -1582.2595, -1623.7994, -1677.4894, -1734.4379, -1783.2451, -1820.1002, -1845.3433, -1857.4204, -1863.7135, -1877.6727, -1903.2032, -1934.5334, -1962.7538, -1982.2228, -1992.1484, -1995.6678, -1992.619, -1970.0658, -1915.6781, -1840.9904, -1768.373, -1697.097, -1619.3698, -1553.3435, -1520.7733, -1514.5142, -1512.3151, -1509.3231, -1509.7914, -1500.1134, -1459.1165, -1381.5653, -1284.494, -1187.2854, -1092.2422, -999.8038, -914.18146, -831.5862, -746.8167, -657.23517, -561.62384, -470.5669, -401.41376, -355.1119, -316.1234, -273.3612, -220.13834, -140.40962, -27.668236, 91.87787, 194.59889, 296.8533, 423.2619, 564.4658, 689.93066, 789.94775, 884.6697, 985.54364, 1071.3992, 1121.791, 1150.5063, 1183.1925, 1224.354, 1264.9, 1297.5225, 1312.7068, 1304.2473, 1285.2727, 1275.0349, 1267.9458, 1240.7292, 1187.8523, 1125.2488, 1066.385, 1009.6876, 940.5224, 854.1314, 773.353, 711.5303, 651.4366, 588.53516, 538.88916, 501.15363, 460.14825, 417.98517, 380.1871, 333.3568, 277.82996, 230.22473, 186.98016, 143.14145, 110.92619, 100.39982, 107.083916, 119.45348, 137.12384, 160.98726, 174.99513, 162.14423, 130.455, 99.70367, 62.298042, 4.0239563, -58.60829, -103.73868, -128.57013, -144.392, -170.60661, -222.13486, -290.05865, -350.91632, -402.0981, -461.86868, -539.67, -625.82086, -707.11646, -778.95703, -844.86743, -916.68207, -997.6924, -1076.9763, -1150.6418, -1219.973, -1282.46, -1339.4653, -1390.8987, -1416.168, -1399.9817, -1376.8962, -1387.8058, -1416.9409, -1424.0131, -1404.2661, -1376.866, -1343.6855, -1300.4259, -1247.3698, -1182.5712, -1117.4323, -1060.2775, -995.8147, -917.5809, -845.83, -796.4136, -758.16846, -709.4432, -638.02594, -551.52637, -469.62595, -393.0194, -309.57413, -224.32016, -150.69379, -91.381134, -34.44581, 37.568058, 125.91611, 209.85504, 270.8642, 314.46622, 356.9047, 406.0201, 466.33603, 539.5211, 622.6745, 710.3698, 786.0053, 835.6237, 866.8232, 888.69714, 900.2288, 909.47723, 932.9227, 969.8758, 997.0238, 1002.7095, 1009.33136, 1048.7474, 1127.7412, 1219.3196, 1292.7708, 1351.3141, 1411.5253, 1465.7561, 1495.715, 1499.3107, 1489.0054, 1472.5387, 1454.7802, 1442.8802, 1432.2278, 1415.7853, 1393.7463, 1366.791, 1334.939, 1297.4614, 1256.5587, 1210.1974, 1156.0198, 1096.314, 1022.3505, 931.98035, 840.32, 748.7633, 643.3313, 535.3086, 452.84384, 381.41998, 293.76593, 202.78804, 115.46181, 2.848444, -151.9073, -315.988, -457.49225, -591.46155, -733.57104, -875.484, -1002.2885, -1102.3705, -1184.0809, -1268.6567, -1360.0754, -1442.1298, -1509.4015, -1572.1705, -1630.7217, -1685.3574, -1752.377, -1837.0332, -1918.3508, -1982.0349, -2037.1409, -2092.9355, -2144.748, -2174.662, -2165.587, -2123.4956, -2071.455, -2016.8064, -1944.9612, -1851.5173, -1746.4093, -1632.6666, -1517.7556, -1421.2119, -1339.8651, -1240.179, -1111.1624, -976.6043, -840.7785, -681.29553, -500.35257, -324.06122, -155.56522, 19.897705, 205.10396, 389.51694, 560.6322, 717.99316, 867.77563, 1009.13904, 1137.5709, 1255.1805, 1365.9401, 1459.4799, 1532.2576, 1601.7274, 1669.4132, 1715.4548, 1736.9218, 1754.1222, 1773.0212, 1781.6361, 1784.0096, 1790.7439, 1790.9458, 1766.7467, 1726.7048, 1691.5796, 1660.4906, 1625.6824, 1576.5885, 1493.2614, 1380.699, 1264.4869, 1138.5354, 976.7996, 789.5482, 608.6704, 441.64578, 282.43655, 132.52983, -8.380628, -143.74124, -273.22894, -404.35336, -539.1669, -655.6166, -743.24457, -817.8242, -894.0151, -973.0729, -1050.8239, -1129.0627, -1205.7386, -1281.3607, -1371.6538, -1479.0549, -1584.6927, -1671.814, -1738.4567, -1796.37, -1858.8871, -1929.8475, -1994.8425, -2030.4064, -2036.6422, -2041.9125, -2065.5054, -2098.5696, -2120.4485, -2115.4963, -2089.7668, -2063.8184, -2039.3445, -2008.1306, -1978.6305, -1954.6621, -1917.1207, -1848.9496, -1749.2766, -1624.4669, -1483.1907, -1332.5011, -1180.8673, -1035.2605, -889.9849, -734.8095, -569.74023, -401.98657, -229.24869, -44.59149, 142.64136, 313.80316, 463.89514, 610.44507, 771.859, 947.2708, ]; assert_eq!(freq_buf, freq_buf_expected); } }