1 /******************************************************************************
2 * *
3 * Copyright (C) 2018 The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 *****************************************************************************
18 * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
19 */
20 #include <ixheaacd_type_def.h>
21 #include "ixheaacd_bitbuffer.h"
22 #include "ixheaacd_config.h"
23
24 #include "ixheaacd_mps_polyphase.h"
25
26 #include "ixheaacd_mps_dec.h"
27 #include "ixheaacd_mps_interface.h"
28 #include <math.h>
29
30 #define max(a, b) ((a) > (b) ? (a) : (b))
31
32 #define min(a, b) ((a) < (b) ? (a) : (b))
33
34 #define DIR_DIFF_IN 0
35 #define DOWNMIX_IN 1
36
37 #define LAMDA (4.0f)
38 #define GES_ALPHA (0.99637864f)
39 #define GES_BETA (0.9643691f)
40
41 extern WORD32
42 ixheaacd_hybrid_band_71_to_processing_band_20_map[MAX_HYBRID_BANDS_MPS];
43
ixheaacd_mps_env_init(ia_mps_dec_state_struct * self)44 VOID ixheaacd_mps_env_init(ia_mps_dec_state_struct *self) {
45 WORD32 i;
46 for (i = 0; i < 3; i++) {
47 self->guided_env_shaping.avg_energy_prev[i] = 32768.f * 32768.f;
48 }
49 }
50
ixheaacd_mps_est_normalized_envelope(ia_mps_dec_state_struct * self,WORD32 inp,WORD32 ch,FLOAT32 * env)51 static VOID ixheaacd_mps_est_normalized_envelope(ia_mps_dec_state_struct *self,
52 WORD32 inp, WORD32 ch,
53 FLOAT32 *env) {
54 FLOAT32 slot_energy[MAX_TIME_SLOTS][MAX_PARAMETER_BANDS] = {{0}};
55 FLOAT32 pb_energy[MAX_PARAMETER_BANDS] = {0};
56 FLOAT32 whitening_weight[MAX_PARAMETER_BANDS];
57 WORD32 ii, jj, param_band;
58
59 WORD32 k_start = 10;
60 WORD32 k_stop = 18;
61
62 FLOAT32 total_energy = 0, avg_energy = 0;
63
64 WORD32 ch_offset;
65
66 switch (inp) {
67 case DIR_DIFF_IN:
68 ch_offset = 0;
69 for (ii = 0; ii < self->time_slots; ii++) {
70 for (jj = 0; jj < self->hyb_band_count; jj++) {
71 slot_energy[ii]
72 [ixheaacd_hybrid_band_71_to_processing_band_20_map[jj]] +=
73 ((self->hyb_dir_out[ch][ii][jj].re +
74 self->hyb_diff_out[ch][ii][jj].re) *
75 (self->hyb_dir_out[ch][ii][jj].re +
76 self->hyb_diff_out[ch][ii][jj].re)) +
77 ((self->hyb_dir_out[ch][ii][jj].im +
78 self->hyb_diff_out[ch][ii][jj].im) *
79 (self->hyb_dir_out[ch][ii][jj].im +
80 self->hyb_diff_out[ch][ii][jj].im));
81 }
82 }
83 break;
84 case DOWNMIX_IN:
85 ch_offset = self->out_ch_count;
86 for (ii = 0; ii < self->time_slots; ii++) {
87 for (jj = 0; jj < self->hyb_band_count; jj++) {
88 slot_energy[ii]
89 [ixheaacd_hybrid_band_71_to_processing_band_20_map[jj]] +=
90 self->hyb_in[ch][ii][jj].re * self->hyb_in[ch][ii][jj].re +
91 self->hyb_in[ch][ii][jj].im * self->hyb_in[ch][ii][jj].im;
92 }
93 }
94 break;
95 default:
96 ch_offset = 0;
97 break;
98 }
99
100 for (param_band = k_start; param_band <= k_stop; param_band++)
101 pb_energy[param_band] =
102 self->guided_env_shaping.pb_energy_prev[ch + ch_offset][param_band];
103
104 avg_energy = self->guided_env_shaping.avg_energy_prev[ch + ch_offset];
105
106 for (ii = 0; ii < self->time_slots; ii++) {
107 total_energy = 0;
108 for (param_band = k_start; param_band <= k_stop; param_band++) {
109 pb_energy[param_band] = (1 - GES_ALPHA) * slot_energy[ii][param_band] +
110 GES_ALPHA * pb_energy[param_band];
111
112 total_energy += slot_energy[ii][param_band];
113 }
114 total_energy /= (k_stop - k_start + 1);
115
116 total_energy =
117 (1 - GES_ALPHA) * total_energy +
118 GES_ALPHA * self->guided_env_shaping.frame_energy_prev[ch + ch_offset];
119
120 self->guided_env_shaping.frame_energy_prev[ch + ch_offset] = total_energy;
121
122 for (param_band = k_start; param_band <= k_stop; param_band++) {
123 whitening_weight[param_band] =
124 total_energy / (pb_energy[param_band] + ABS_THR);
125 }
126
127 env[ii] = 0;
128 for (param_band = k_start; param_band <= k_stop; param_band++) {
129 env[ii] += slot_energy[ii][param_band] * whitening_weight[param_band];
130 }
131
132 avg_energy = (1 - GES_BETA) * env[ii] + GES_BETA * avg_energy;
133
134 env[ii] = (FLOAT32)sqrt(env[ii] / (avg_energy + ABS_THR));
135 }
136
137 for (param_band = k_start; param_band <= k_stop; param_band++)
138 self->guided_env_shaping.pb_energy_prev[ch + ch_offset][param_band] =
139 pb_energy[param_band];
140
141 self->guided_env_shaping.avg_energy_prev[ch + ch_offset] = avg_energy;
142 }
143
ixheaacd_mps_time_env_shaping(ia_mps_dec_state_struct * self)144 VOID ixheaacd_mps_time_env_shaping(ia_mps_dec_state_struct *self) {
145 FLOAT32 dir_energy[MAX_TIME_SLOTS];
146 FLOAT32 dmx_energy[MAX_TIME_SLOTS];
147 WORD32 ch, time_slot, jj;
148
149 WORD32 band_start;
150 FLOAT32 gain, ratio;
151
152 FLOAT32 amp_direct = 0;
153 FLOAT32 amp_diff = 0;
154 FLOAT32 amp_ratio;
155
156 band_start = 6;
157
158 ixheaacd_mps_est_normalized_envelope(self, DOWNMIX_IN, 0, dmx_energy);
159
160 for (ch = 0; ch < self->out_ch_count; ch++) {
161 ixheaacd_mps_est_normalized_envelope(self, DIR_DIFF_IN, ch, dir_energy);
162
163 if (self->temp_shape_enable_ch_ges[ch]) {
164 for (time_slot = 0; time_slot < self->time_slots; time_slot++) {
165 gain = self->env_shape_data[ch][time_slot] * dmx_energy[time_slot] /
166 (dir_energy[time_slot] + 1e-9f);
167
168 amp_direct = 0;
169 amp_diff = 0;
170
171 for (jj = band_start; jj < self->hyb_band_count; jj++) {
172 amp_direct += self->hyb_dir_out[ch][time_slot][jj].re *
173 self->hyb_dir_out[ch][time_slot][jj].re +
174 self->hyb_dir_out[ch][time_slot][jj].im *
175 self->hyb_dir_out[ch][time_slot][jj].im;
176
177 amp_diff += self->hyb_diff_out[ch][time_slot][jj].re *
178 self->hyb_diff_out[ch][time_slot][jj].re +
179 self->hyb_diff_out[ch][time_slot][jj].im *
180 self->hyb_diff_out[ch][time_slot][jj].im;
181 }
182
183 amp_ratio = (FLOAT32)sqrt(amp_diff / (amp_direct + ABS_THR));
184
185 ratio = min(max((gain + amp_ratio * (gain - 1)), 1 / LAMDA), LAMDA);
186
187 for (jj = band_start; jj < self->hyb_band_count; jj++) {
188 self->hyb_dir_out[ch][time_slot][jj].re *= ratio;
189 self->hyb_dir_out[ch][time_slot][jj].im *= ratio;
190 }
191 }
192 }
193 }
194 }
195