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 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 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 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