1 // Vorbis decoder written in Rust
2 //
3 // Copyright (c) 2016 est31 <MTest31@outlook.com>
4 // and contributors. All rights reserved.
5 // Licensed under MIT license, or Apache 2 license,
6 // at your option. Please see the LICENSE file
7 // attached to this source distribution for details.
8
9 /*!
10 Cached header info
11
12 This mod contains logic to generate and deal with
13 data derived from header information
14 that's used later in the decode process.
15
16 The caching is done to speed up decoding.
17 */
18
19 pub struct TwiddleFactors {
20 pub a :Vec<f32>,
21 pub b :Vec<f32>,
22 pub c :Vec<f32>,
23 }
24
25 pub struct CachedBlocksizeDerived {
26 pub twiddle_factors : TwiddleFactors,
27 pub window_slope : Vec<f32>,
28 pub bitrev : Vec<u32>,
29 }
30
31 impl CachedBlocksizeDerived {
from_blocksize(bs :u8) -> Self32 pub fn from_blocksize(bs :u8) -> Self {
33 CachedBlocksizeDerived {
34 window_slope : generate_window((1 << (bs as u16)) >> 1),
35 twiddle_factors : compute_twiddle_factors(bs),
36 bitrev : compute_bitreverse(bs),
37 }
38 }
39 }
40
win_slope(x :u16, n :u16) -> f3241 fn win_slope(x :u16, n :u16) -> f32 {
42 // please note that there might be a MISTAKE
43 // in how the spec specifies the right window slope
44 // function. See "4.3.1. packet type, mode and window decode"
45 // step 7 where it adds an "extra" pi/2.
46 // The left slope doesn't have it, only the right one.
47 // as stb_vorbis shares the window slope generation function,
48 // The *other* possible reason is that we don't need the right
49 // window for anything. TODO investigate this more.
50 let v = (0.5 * std::f32::consts::PI * (x as f32 + 0.5) / n as f32).sin();
51 return (0.5 * std::f32::consts::PI * v * v ).sin();
52 }
53
generate_window(n :u16) -> Vec<f32>54 fn generate_window(n :u16) -> Vec<f32> {
55 let mut window = Vec::with_capacity(n as usize);
56 for i in 0 .. n {
57 window.push(win_slope(i, n));
58 }
59 return window;
60 }
61
compute_twiddle_factors(blocksize :u8) -> TwiddleFactors62 fn compute_twiddle_factors(blocksize :u8) -> TwiddleFactors {
63 let n = 1 << (blocksize as u16);
64
65 let n2 = n >> 1;
66 let n4 = n >> 2;
67 let n8 = n >> 3;
68
69 let mut a = Vec::with_capacity(n2);
70 let mut b = Vec::with_capacity(n2);
71 let mut c = Vec::with_capacity(n4);
72
73 let mut k2 = 0;
74
75 let pi_4_n = 4.0 * std::f32::consts::PI / (n as f32);
76 let pi_05_n = 0.5 * std::f32::consts::PI / (n as f32);
77 let pi_2_n = 2.0 * std::f32::consts::PI / (n as f32);
78
79 for k in 0..n4 {
80 a.push( f32::cos((k as f32) * pi_4_n));
81 a.push(-f32::sin((k as f32) * pi_4_n));
82 b.push( f32::cos(((k2+1) as f32) * pi_05_n) * 0.5);
83 b.push( f32::sin(((k2+1) as f32) * pi_05_n) * 0.5);
84 k2 += 2;
85 }
86 k2 = 0;
87 for _ in 0..n8 {
88 c.push( f32::cos(((k2 + 1) as f32) * pi_2_n));
89 c.push(-f32::sin(((k2 + 1) as f32) * pi_2_n));
90 k2 += 2;
91 }
92 return TwiddleFactors {
93 a,
94 b,
95 c,
96 };
97 }
98
compute_bitreverse(blocksize :u8) -> Vec<u32>99 fn compute_bitreverse(blocksize :u8) -> Vec<u32> {
100 let ld = blocksize as u16;
101 let n = 1 << blocksize;
102 let n8 = n >> 3;
103 let mut rev = Vec::with_capacity(n8);
104 for i in 0 .. n8 {
105 rev.push((::bit_reverse(i as u32) as u32 >> (32 - ld + 3)) << 2);
106 }
107 return rev;
108 }
109
110 #[test]
test_compute_bitreverse()111 fn test_compute_bitreverse() {
112 let br = compute_bitreverse(8);
113 // The output was generated from the output of the
114 // original stb_vorbis function.
115 let cmp_arr = &[
116 0, 64, 32, 96,
117 16, 80, 48, 112,
118 8, 72, 40, 104,
119 24, 88, 56, 120,
120 4, 68, 36, 100,
121 20, 84, 52, 116,
122 12, 76, 44, 108,
123 28, 92, 60, 124];
124 assert_eq!(br, cmp_arr);
125 }
126
127 #[inline]
bark(x :f32) -> f32128 fn bark(x :f32) -> f32 {
129 13.1 * (0.00074 * x).atan() + 2.24 * (0.0000000185*x*x).atan() + 0.0001 * x
130 }
131
132 /// Precomputes bark map values used by floor type 0 packets
133 ///
134 /// Precomputes the cos(omega) values for use by floor type 0 computation.
135 ///
136 /// Note that there is one small difference to the spec: the output
137 /// vec is n elements long, not n+1. The last element (at index n)
138 /// is -1 in the spec, we lack it. Users of the result of this function
139 /// implementation should use it "virtually".
compute_bark_map_cos_omega(n :u16, floor0_rate :u16, floor0_bark_map_size :u16) -> Vec<f32>140 pub fn compute_bark_map_cos_omega(n :u16, floor0_rate :u16,
141 floor0_bark_map_size :u16) -> Vec<f32> {
142 let mut res = Vec::with_capacity(n as usize);
143 let hfl = floor0_rate as f32 / 2.0;
144 let hfl_dn = hfl / n as f32;
145 let foobar_const_part = floor0_bark_map_size as f32 / bark(hfl);
146 // Bark map size minus 1:
147 let bms_m1 = floor0_bark_map_size as f32 - 1.0;
148 let omega_factor = std::f32::consts::PI / floor0_bark_map_size as f32;
149 for i in 0 .. n {
150 let foobar = (bark(i as f32 * hfl_dn) * foobar_const_part).floor();
151 let map_elem = foobar.min(bms_m1);
152 let cos_omega = (map_elem * omega_factor).cos();
153 res.push(cos_omega);
154 }
155 return res;
156 }
157