xref: /aosp_15_r20/external/libxaac/encoder/ixheaace_mps_dmx_tdom_enh.c (revision 15dc779a375ca8b5125643b829a8aa4b70d7f451)
1 /******************************************************************************
2  *                                                                            *
3  * Copyright (C) 2023 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 
21 #include <math.h>
22 #include "ixheaac_type_def.h"
23 #include "ixheaac_constants.h"
24 #include "ixheaac_error_standards.h"
25 #include "ixheaace_error_codes.h"
26 #include "ixheaace_mps_common_fix.h"
27 
28 #include "ixheaace_mps_common_define.h"
29 #include "ixheaace_mps_defines.h"
30 #include "ixheaac_constants.h"
31 #include "ixheaace_mps_dmx_tdom_enh.h"
32 #include "ixheaac_basic_ops32.h"
33 #include "ixheaac_basic_ops40.h"
34 #include "ixheaac_basic_ops.h"
35 
ixheaace_mps_212_calculate_ratio(const FLOAT32 sqrt_lin_cld_m,const FLOAT32 lin_cld_m,const FLOAT32 icc_m,FLOAT32 g_m[2])36 static VOID ixheaace_mps_212_calculate_ratio(const FLOAT32 sqrt_lin_cld_m,
37                                              const FLOAT32 lin_cld_m, const FLOAT32 icc_m,
38                                              FLOAT32 g_m[2]) {
39   if (icc_m >= 0.f) {
40     g_m[0] = g_m[1] = 1.0f;
41   } else {
42     FLOAT32 max_gain_factor = 2.0f;
43     FLOAT32 numerator, denominator;
44     FLOAT32 q = 0.0f;
45     numerator = (lin_cld_m + 0.5f) + (icc_m * sqrt_lin_cld_m);
46     denominator = (lin_cld_m + 0.5f) - (icc_m * sqrt_lin_cld_m);
47 
48     if ((numerator > (0.f)) && (denominator > (0.f))) {
49       FLOAT32 intermediate;
50       intermediate = numerator / denominator;
51       intermediate = (FLOAT32)sqrt(intermediate);
52       intermediate = (FLOAT32)sqrt(intermediate);
53       q = (intermediate >= max_gain_factor) ? max_gain_factor : intermediate;
54     }
55 
56     g_m[0] = max_gain_factor - q;
57     g_m[1] = q;
58   }
59 }
60 
ixheaace_mps_212_calculate_dmx_gains(const FLOAT32 lin_cld_m,const FLOAT32 lin_cld_2_m,const FLOAT32 icc_m,const FLOAT32 g_m[2],FLOAT32 h_1_m[2])61 static VOID ixheaace_mps_212_calculate_dmx_gains(const FLOAT32 lin_cld_m,
62                                                  const FLOAT32 lin_cld_2_m, const FLOAT32 icc_m,
63                                                  const FLOAT32 g_m[2], FLOAT32 h_1_m[2]) {
64   const FLOAT32 max_gain_factor = 2.0f;
65   FLOAT32 energy_right, energy_left, cross_energy, inverse_weight_num, inverse_weight_den,
66       inverse_weight, inverse_weight_limited;
67   energy_right = lin_cld_2_m - 0.5f;
68   energy_right = (FLOAT32)sqrt(energy_right);
69   energy_left = lin_cld_m * energy_right;
70   cross_energy = (FLOAT32)sqrt(energy_left * energy_right);
71   inverse_weight_num = energy_right + energy_left;
72   inverse_weight_den = ((g_m[0] * g_m[0]) * energy_left) + ((g_m[1] * g_m[1]) * energy_right);
73 
74   inverse_weight_den = ((((g_m[0] * g_m[1]) * cross_energy) * icc_m) * 2) + inverse_weight_den;
75 
76   if (inverse_weight_den > (0.f)) {
77     inverse_weight = inverse_weight_num / inverse_weight_den;
78 
79     inverse_weight = (FLOAT32)sqrt(inverse_weight);
80 
81     inverse_weight_limited =
82         (inverse_weight >= max_gain_factor) ? max_gain_factor : inverse_weight;
83   } else {
84     inverse_weight_limited = max_gain_factor;
85   }
86 
87   h_1_m[1] = g_m[1] * inverse_weight_limited;
88   h_1_m[0] = g_m[0] * inverse_weight_limited;
89 }
90 
ixheaace_mps_212_init_enhanced_time_domain_dmx(ixheaace_mps_pstr_enhanced_time_domain_dmx pstr_enhanced_time_domain_dmx,const FLOAT32 * const ptr_input_gain_m_flt,const FLOAT32 output_gain_m_flt,const WORD32 frame_length)91 IA_ERRORCODE ixheaace_mps_212_init_enhanced_time_domain_dmx(
92     ixheaace_mps_pstr_enhanced_time_domain_dmx pstr_enhanced_time_domain_dmx,
93     const FLOAT32 *const ptr_input_gain_m_flt, const FLOAT32 output_gain_m_flt,
94     const WORD32 frame_length) {
95   IA_ERRORCODE error = IA_NO_ERROR;
96   WORD32 sample_idx;
97   FLOAT32 delta;
98   if (frame_length > pstr_enhanced_time_domain_dmx->max_frame_length) {
99     return IA_EXHEAACE_INIT_FATAL_MPS_INIT_FAILED;
100   }
101   pstr_enhanced_time_domain_dmx->frame_length = frame_length;
102   delta = (FLOAT32)(PI_FLT / (2.0 * pstr_enhanced_time_domain_dmx->frame_length));
103   for (sample_idx = 0; sample_idx < pstr_enhanced_time_domain_dmx->frame_length + 1;
104        sample_idx++) {
105     FLOAT32 sin_val = (FLOAT32)sin(sample_idx * delta);
106     pstr_enhanced_time_domain_dmx->sinus_window[sample_idx] = ALPHA * sin_val * sin_val;
107   }
108 
109   pstr_enhanced_time_domain_dmx->prev_left_energy =
110       pstr_enhanced_time_domain_dmx->prev_right_energy =
111           pstr_enhanced_time_domain_dmx->prev_x_energy = 0.0f;
112   pstr_enhanced_time_domain_dmx->cld_weight =
113       (ptr_input_gain_m_flt[LEFT_CH]) / (ptr_input_gain_m_flt[RIGHT_CH]);
114   pstr_enhanced_time_domain_dmx->gain_weight[LEFT_CH] =
115       (ptr_input_gain_m_flt[LEFT_CH] * output_gain_m_flt);
116   pstr_enhanced_time_domain_dmx->gain_weight[RIGHT_CH] =
117       (ptr_input_gain_m_flt[RIGHT_CH] * output_gain_m_flt);
118   pstr_enhanced_time_domain_dmx->prev_gain[LEFT_CH] =
119       pstr_enhanced_time_domain_dmx->gain_weight[LEFT_CH];
120   pstr_enhanced_time_domain_dmx->prev_gain[RIGHT_CH] =
121       pstr_enhanced_time_domain_dmx->gain_weight[RIGHT_CH];
122   pstr_enhanced_time_domain_dmx->prev_h1[LEFT_CH] =
123       pstr_enhanced_time_domain_dmx->gain_weight[LEFT_CH];
124   pstr_enhanced_time_domain_dmx->prev_h1[RIGHT_CH] =
125       pstr_enhanced_time_domain_dmx->gain_weight[RIGHT_CH];
126   return error;
127 }
128 
ixheaace_mps_212_apply_enhanced_time_domain_dmx(ixheaace_mps_pstr_enhanced_time_domain_dmx pstr_enhanced_time_domain_dmx,FLOAT32 input_time[2][MPS_MAX_FRAME_LENGTH+MAX_DELAY_SURROUND_ANALYSIS],FLOAT32 * const ptr_output_time_dmx,const WORD32 input_delay)129 IA_ERRORCODE ixheaace_mps_212_apply_enhanced_time_domain_dmx(
130     ixheaace_mps_pstr_enhanced_time_domain_dmx pstr_enhanced_time_domain_dmx,
131     FLOAT32 input_time[2][MPS_MAX_FRAME_LENGTH + MAX_DELAY_SURROUND_ANALYSIS],
132     FLOAT32 *const ptr_output_time_dmx, const WORD32 input_delay) {
133   IA_ERRORCODE error = IA_NO_ERROR;
134 
135   WORD32 sample_idx;
136   FLOAT32 lin_bb_cld, lin_cld, corr, sqrt_lin_cld, g[2], h1[2], gain_left, gain_right;
137   FLOAT32 prev_energy_left, prev_energy_right, prev_energy, energy_left, energy_right, energy_out;
138   WORD32 granule_length = MIN(128, pstr_enhanced_time_domain_dmx->frame_length);
139 
140   sample_idx = 0;
141   prev_energy_left = prev_energy_right = prev_energy = .5f;
142 
143   do {
144     WORD32 offset = sample_idx;
145     FLOAT32 partial_left, partial_right, partial_out;
146     partial_left = partial_right = partial_out = 0.0;
147 
148     WORD32 value = MIN(offset + granule_length, pstr_enhanced_time_domain_dmx->frame_length);
149     for (sample_idx = offset; sample_idx < value; sample_idx++) {
150       FLOAT32 input_left = input_time[LEFT_CH][sample_idx];
151       FLOAT32 input_right = input_time[RIGHT_CH][sample_idx];
152 
153       partial_left += (FLOAT32)pow(input_left, 2);
154       partial_right += (FLOAT32)pow(input_right, 2);
155       partial_out += input_left * input_right;
156     }
157 
158     prev_energy_left = prev_energy_left + partial_left;
159     prev_energy_right = prev_energy_right + partial_right;
160     prev_energy = prev_energy + partial_out;
161 
162   } while (sample_idx < pstr_enhanced_time_domain_dmx->frame_length);
163 
164   energy_left = pstr_enhanced_time_domain_dmx->prev_left_energy + prev_energy_left;
165   energy_right = pstr_enhanced_time_domain_dmx->prev_right_energy + prev_energy_right;
166   energy_out = pstr_enhanced_time_domain_dmx->prev_x_energy + prev_energy;
167 
168   lin_bb_cld = pstr_enhanced_time_domain_dmx->cld_weight * (energy_left / energy_right);
169   corr = energy_out * (1 / (FLOAT32)sqrt(energy_left * energy_right));
170 
171   pstr_enhanced_time_domain_dmx->prev_left_energy = prev_energy_left;
172   pstr_enhanced_time_domain_dmx->prev_right_energy = prev_energy_right;
173   pstr_enhanced_time_domain_dmx->prev_x_energy = prev_energy;
174 
175   lin_cld = (FLOAT32)sqrt(lin_bb_cld);
176   sqrt_lin_cld = (FLOAT32)sqrt(lin_cld);
177 
178   ixheaace_mps_212_calculate_ratio(sqrt_lin_cld, lin_cld, corr, g);
179 
180   ixheaace_mps_212_calculate_dmx_gains(lin_cld, lin_bb_cld, corr, g, h1);
181 
182   h1[LEFT_CH] = h1[LEFT_CH] * pstr_enhanced_time_domain_dmx->gain_weight[LEFT_CH];
183   h1[RIGHT_CH] = h1[RIGHT_CH] * pstr_enhanced_time_domain_dmx->gain_weight[RIGHT_CH];
184 
185   gain_left = pstr_enhanced_time_domain_dmx->prev_gain[LEFT_CH];
186   gain_right = pstr_enhanced_time_domain_dmx->prev_gain[RIGHT_CH];
187 
188   for (sample_idx = 0; sample_idx < pstr_enhanced_time_domain_dmx->frame_length; sample_idx++) {
189     WORD32 frame_length = pstr_enhanced_time_domain_dmx->frame_length;
190     FLOAT32 intermediate_gain_left, intermediate_gain_right, temp;
191 
192     intermediate_gain_left =
193         ((pstr_enhanced_time_domain_dmx->sinus_window[sample_idx] * h1[LEFT_CH]) +
194          (pstr_enhanced_time_domain_dmx->sinus_window[frame_length - sample_idx] *
195           pstr_enhanced_time_domain_dmx->prev_h1[LEFT_CH]));
196 
197     intermediate_gain_right =
198         ((pstr_enhanced_time_domain_dmx->sinus_window[sample_idx] * h1[RIGHT_CH]) +
199          (pstr_enhanced_time_domain_dmx->sinus_window[frame_length - sample_idx] *
200           pstr_enhanced_time_domain_dmx->prev_h1[RIGHT_CH]));
201 
202     gain_left = intermediate_gain_left + ((1.f - ALPHA) * gain_left);
203     gain_right = intermediate_gain_right + ((1.f - ALPHA) * gain_right);
204     temp = (gain_left * (FLOAT32)input_time[LEFT_CH][sample_idx + input_delay]) +
205            (gain_right * (FLOAT32)input_time[RIGHT_CH][sample_idx + input_delay]);
206     ptr_output_time_dmx[sample_idx] = (FLOAT32)temp;
207   }
208 
209   pstr_enhanced_time_domain_dmx->prev_gain[LEFT_CH] = gain_left;
210   pstr_enhanced_time_domain_dmx->prev_gain[RIGHT_CH] = gain_right;
211   pstr_enhanced_time_domain_dmx->prev_h1[LEFT_CH] = h1[LEFT_CH];
212   pstr_enhanced_time_domain_dmx->prev_h1[RIGHT_CH] = h1[RIGHT_CH];
213 
214   return error;
215 }
216