1/*
2 * Header file for hardcoded Parametric Stereo tables
3 *
4 * Copyright (c) 2010 Alex Converse <alex.converse@gmail.com>
5 *
6 * This file is part of FFmpeg.
7 *
8 * FFmpeg is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * FFmpeg is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with FFmpeg; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23#ifndef AACPS_TABLEGEN_H
24#define AACPS_TABLEGEN_H
25
26#include <math.h>
27#include <stdint.h>
28
29#if CONFIG_HARDCODED_TABLES
30#define ps_tableinit()
31#define TABLE_CONST const
32#include "libavcodec/aacps_tables.h"
33#else
34#include "libavutil/common.h"
35#include "libavutil/libm.h"
36#include "libavutil/mathematics.h"
37#include "libavutil/mem.h"
38#define NR_ALLPASS_BANDS20 30
39#define NR_ALLPASS_BANDS34 50
40#define PS_AP_LINKS 3
41#define TABLE_CONST
42static float pd_re_smooth[8*8*8];
43static float pd_im_smooth[8*8*8];
44static float HA[46][8][4];
45static float HB[46][8][4];
46static DECLARE_ALIGNED(16, float, f20_0_8) [ 8][8][2];
47static DECLARE_ALIGNED(16, float, f34_0_12)[12][8][2];
48static DECLARE_ALIGNED(16, float, f34_1_8) [ 8][8][2];
49static DECLARE_ALIGNED(16, float, f34_2_4) [ 4][8][2];
50static TABLE_CONST DECLARE_ALIGNED(16, float, Q_fract_allpass)[2][50][3][2];
51static DECLARE_ALIGNED(16, float, phi_fract)[2][50][2];
52
53static const float g0_Q8[] = {
54    0.00746082949812f, 0.02270420949825f, 0.04546865930473f, 0.07266113929591f,
55    0.09885108575264f, 0.11793710567217f, 0.125f
56};
57
58static const float g0_Q12[] = {
59    0.04081179924692f, 0.03812810994926f, 0.05144908135699f, 0.06399831151592f,
60    0.07428313801106f, 0.08100347892914f, 0.08333333333333f
61};
62
63static const float g1_Q8[] = {
64    0.01565675600122f, 0.03752716391991f, 0.05417891378782f, 0.08417044116767f,
65    0.10307344158036f, 0.12222452249753f, 0.125f
66};
67
68static const float g2_Q4[] = {
69    -0.05908211155639f, -0.04871498374946f, 0.0f,   0.07778723915851f,
70     0.16486303567403f,  0.23279856662996f, 0.25f
71};
72
73static void make_filters_from_proto(float (*filter)[8][2], const float *proto, int bands)
74{
75    int q, n;
76    for (q = 0; q < bands; q++) {
77        for (n = 0; n < 7; n++) {
78            double theta = 2 * M_PI * (q + 0.5) * (n - 6) / bands;
79            filter[q][n][0] = proto[n] *  cos(theta);
80            filter[q][n][1] = proto[n] * -sin(theta);
81        }
82    }
83}
84
85static void ps_tableinit(void)
86{
87    static const float ipdopd_sin[] = { 0, M_SQRT1_2, 1,  M_SQRT1_2,  0, -M_SQRT1_2, -1, -M_SQRT1_2 };
88    static const float ipdopd_cos[] = { 1, M_SQRT1_2, 0, -M_SQRT1_2, -1, -M_SQRT1_2,  0,  M_SQRT1_2 };
89    int pd0, pd1, pd2;
90
91    static const float iid_par_dequant[] = {
92        //iid_par_dequant_default
93        0.05623413251903, 0.12589254117942, 0.19952623149689, 0.31622776601684,
94        0.44668359215096, 0.63095734448019, 0.79432823472428, 1,
95        1.25892541179417, 1.58489319246111, 2.23872113856834, 3.16227766016838,
96        5.01187233627272, 7.94328234724282, 17.7827941003892,
97        //iid_par_dequant_fine
98        0.00316227766017, 0.00562341325190, 0.01,             0.01778279410039,
99        0.03162277660168, 0.05623413251903, 0.07943282347243, 0.11220184543020,
100        0.15848931924611, 0.22387211385683, 0.31622776601684, 0.39810717055350,
101        0.50118723362727, 0.63095734448019, 0.79432823472428, 1,
102        1.25892541179417, 1.58489319246111, 1.99526231496888, 2.51188643150958,
103        3.16227766016838, 4.46683592150963, 6.30957344480193, 8.91250938133745,
104        12.5892541179417, 17.7827941003892, 31.6227766016838, 56.2341325190349,
105        100,              177.827941003892, 316.227766016837,
106    };
107    static const float icc_invq[] = {
108        1, 0.937,      0.84118,    0.60092,    0.36764,   0,      -0.589,    -1
109    };
110    static const float acos_icc_invq[] = {
111        0, 0.35685527, 0.57133466, 0.92614472, 1.1943263, M_PI/2, 2.2006171, M_PI
112    };
113    int iid, icc;
114
115    int k, m;
116    static const int8_t f_center_20[] = {
117        -3, -1, 1, 3, 5, 7, 10, 14, 18, 22,
118    };
119    static const int8_t f_center_34[] = {
120         2,  6, 10, 14, 18, 22, 26, 30,
121        34,-10, -6, -2, 51, 57, 15, 21,
122        27, 33, 39, 45, 54, 66, 78, 42,
123       102, 66, 78, 90,102,114,126, 90,
124    };
125    static const float fractional_delay_links[] = { 0.43f, 0.75f, 0.347f };
126    const float fractional_delay_gain = 0.39f;
127
128    for (pd0 = 0; pd0 < 8; pd0++) {
129        float pd0_re = ipdopd_cos[pd0];
130        float pd0_im = ipdopd_sin[pd0];
131        for (pd1 = 0; pd1 < 8; pd1++) {
132            float pd1_re = ipdopd_cos[pd1];
133            float pd1_im = ipdopd_sin[pd1];
134            for (pd2 = 0; pd2 < 8; pd2++) {
135                float pd2_re = ipdopd_cos[pd2];
136                float pd2_im = ipdopd_sin[pd2];
137                float re_smooth = 0.25f * pd0_re + 0.5f * pd1_re + pd2_re;
138                float im_smooth = 0.25f * pd0_im + 0.5f * pd1_im + pd2_im;
139                float pd_mag = 1 / sqrt(im_smooth * im_smooth + re_smooth * re_smooth);
140                pd_re_smooth[pd0*64+pd1*8+pd2] = re_smooth * pd_mag;
141                pd_im_smooth[pd0*64+pd1*8+pd2] = im_smooth * pd_mag;
142            }
143        }
144    }
145
146    for (iid = 0; iid < 46; iid++) {
147        float c = iid_par_dequant[iid]; ///< Linear Inter-channel Intensity Difference
148        float c1 = (float)M_SQRT2 / sqrtf(1.0f + c*c);
149        float c2 = c * c1;
150        for (icc = 0; icc < 8; icc++) {
151            /*if (PS_BASELINE || ps->icc_mode < 3)*/ {
152                float alpha = 0.5f * acos_icc_invq[icc];
153                float beta  = alpha * (c1 - c2) * (float)M_SQRT1_2;
154                HA[iid][icc][0] = c2 * cosf(beta + alpha);
155                HA[iid][icc][1] = c1 * cosf(beta - alpha);
156                HA[iid][icc][2] = c2 * sinf(beta + alpha);
157                HA[iid][icc][3] = c1 * sinf(beta - alpha);
158            } /* else */ {
159                float alpha, gamma, mu, rho;
160                float alpha_c, alpha_s, gamma_c, gamma_s;
161                rho = FFMAX(icc_invq[icc], 0.05f);
162                alpha = 0.5f * atan2f(2.0f * c * rho, c*c - 1.0f);
163                mu = c + 1.0f / c;
164                mu = sqrtf(1 + (4 * rho * rho - 4)/(mu * mu));
165                gamma = atanf(sqrtf((1.0f - mu)/(1.0f + mu)));
166                if (alpha < 0) alpha += M_PI/2;
167                alpha_c = cosf(alpha);
168                alpha_s = sinf(alpha);
169                gamma_c = cosf(gamma);
170                gamma_s = sinf(gamma);
171                HB[iid][icc][0] =  M_SQRT2 * alpha_c * gamma_c;
172                HB[iid][icc][1] =  M_SQRT2 * alpha_s * gamma_c;
173                HB[iid][icc][2] = -M_SQRT2 * alpha_s * gamma_s;
174                HB[iid][icc][3] =  M_SQRT2 * alpha_c * gamma_s;
175            }
176        }
177    }
178
179    for (k = 0; k < NR_ALLPASS_BANDS20; k++) {
180        double f_center, theta;
181        if (k < FF_ARRAY_ELEMS(f_center_20))
182            f_center = f_center_20[k] * 0.125;
183        else
184            f_center = k - 6.5f;
185        for (m = 0; m < PS_AP_LINKS; m++) {
186            theta = -M_PI * fractional_delay_links[m] * f_center;
187            Q_fract_allpass[0][k][m][0] = cos(theta);
188            Q_fract_allpass[0][k][m][1] = sin(theta);
189        }
190        theta = -M_PI*fractional_delay_gain*f_center;
191        phi_fract[0][k][0] = cos(theta);
192        phi_fract[0][k][1] = sin(theta);
193    }
194    for (k = 0; k < NR_ALLPASS_BANDS34; k++) {
195        double f_center, theta;
196        if (k < FF_ARRAY_ELEMS(f_center_34))
197            f_center = f_center_34[k] / 24.0;
198        else
199            f_center = k - 26.5f;
200        for (m = 0; m < PS_AP_LINKS; m++) {
201            theta = -M_PI * fractional_delay_links[m] * f_center;
202            Q_fract_allpass[1][k][m][0] = cos(theta);
203            Q_fract_allpass[1][k][m][1] = sin(theta);
204        }
205        theta = -M_PI*fractional_delay_gain*f_center;
206        phi_fract[1][k][0] = cos(theta);
207        phi_fract[1][k][1] = sin(theta);
208    }
209
210    make_filters_from_proto(f20_0_8,  g0_Q8,   8);
211    make_filters_from_proto(f34_0_12, g0_Q12, 12);
212    make_filters_from_proto(f34_1_8,  g1_Q8,   8);
213    make_filters_from_proto(f34_2_4,  g2_Q4,   4);
214}
215#endif /* CONFIG_HARDCODED_TABLES */
216
217#endif /* AACPS_TABLEGEN_H */
218