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.
89/*!
10Cached header info
1112This mod contains logic to generate and deal with
13data derived from header information
14that's used later in the decode process.
1516The caching is done to speed up decoding.
17*/
1819pub struct TwiddleFactors {
20pub a :Vec<f32>,
21pub b :Vec<f32>,
22pub c :Vec<f32>,
23}
2425pub struct CachedBlocksizeDerived {
26pub twiddle_factors : TwiddleFactors,
27pub window_slope : Vec<f32>,
28pub bitrev : Vec<u32>,
29}
3031impl CachedBlocksizeDerived {
32pub 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}
4041fn 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.
50let v = (0.5 * std::f32::consts::PI * (x as f32 + 0.5) / n as f32).sin();
51return (0.5 * std::f32::consts::PI * v * v ).sin();
52}
5354fn generate_window(n :u16) -> Vec<f32> {
55let mut window = Vec::with_capacity(n as usize);
56for i in 0 .. n {
57 window.push(win_slope(i, n));
58 }
59return window;
60}
6162fn compute_twiddle_factors(blocksize :u8) -> TwiddleFactors {
63let n = 1 << (blocksize as u16);
6465let n2 = n >> 1;
66let n4 = n >> 2;
67let n8 = n >> 3;
6869let mut a = Vec::with_capacity(n2);
70let mut b = Vec::with_capacity(n2);
71let mut c = Vec::with_capacity(n4);
7273let mut k2 = 0;
7475let pi_4_n = 4.0 * std::f32::consts::PI / (n as f32);
76let pi_05_n = 0.5 * std::f32::consts::PI / (n as f32);
77let pi_2_n = 2.0 * std::f32::consts::PI / (n as f32);
7879for 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;
87for _ 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 }
92return TwiddleFactors {
93 a,
94 b,
95 c,
96 };
97}
9899fn compute_bitreverse(blocksize :u8) -> Vec<u32> {
100let ld = blocksize as u16;
101let n = 1 << blocksize;
102let n8 = n >> 3;
103let mut rev = Vec::with_capacity(n8);
104for i in 0 .. n8 {
105 rev.push((::bit_reverse(i as u32) as u32 >> (32 - ld + 3)) << 2);
106 }
107return rev;
108}
109110#[test]
111fn test_compute_bitreverse() {
112let br = compute_bitreverse(8);
113// The output was generated from the output of the
114 // original stb_vorbis function.
115let cmp_arr = &[
1160, 64, 32, 96,
11716, 80, 48, 112,
1188, 72, 40, 104,
11924, 88, 56, 120,
1204, 68, 36, 100,
12120, 84, 52, 116,
12212, 76, 44, 108,
12328, 92, 60, 124];
124assert_eq!(br, cmp_arr);
125}
126127#[inline]
128fn bark(x :f32) -> f32 {
12913.1 * (0.00074 * x).atan() + 2.24 * (0.0000000185*x*x).atan() + 0.0001 * x
130}
131132/// 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".
140pub fn compute_bark_map_cos_omega(n :u16, floor0_rate :u16,
141 floor0_bark_map_size :u16) -> Vec<f32> {
142let mut res = Vec::with_capacity(n as usize);
143let hfl = floor0_rate as f32 / 2.0;
144let hfl_dn = hfl / n as f32;
145let foobar_const_part = floor0_bark_map_size as f32 / bark(hfl);
146// Bark map size minus 1:
147let bms_m1 = floor0_bark_map_size as f32 - 1.0;
148let omega_factor = std::f32::consts::PI / floor0_bark_map_size as f32;
149for i in 0 .. n {
150let foobar = (bark(i as f32 * hfl_dn) * foobar_const_part).floor();
151let map_elem = foobar.min(bms_m1);
152let cos_omega = (map_elem * omega_factor).cos();
153 res.push(cos_omega);
154 }
155return res;
156}