Line data Source code
1 : /******************************************************************************************************
2 :
3 : (C) 2022-2025 IVAS codec Public Collaboration with portions copyright Dolby International AB, Ericsson AB,
4 : Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD.,
5 : Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange,
6 : Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other
7 : contributors to this repository. All Rights Reserved.
8 :
9 : This software is protected by copyright law and by international treaties.
10 : The IVAS codec Public Collaboration consisting of Dolby International AB, Ericsson AB,
11 : Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V., Huawei Technologies Co. LTD.,
12 : Koninklijke Philips N.V., Nippon Telegraph and Telephone Corporation, Nokia Technologies Oy, Orange,
13 : Panasonic Holdings Corporation, Qualcomm Technologies, Inc., VoiceAge Corporation, and other
14 : contributors to this repository retain full ownership rights in their respective contributions in
15 : the software. This notice grants no license of any kind, including but not limited to patent
16 : license, nor is any license granted by implication, estoppel or otherwise.
17 :
18 : Contributors are required to enter into the IVAS codec Public Collaboration agreement before making
19 : contributions.
20 :
21 : This software is provided "AS IS", without any express or implied warranties. The software is in the
22 : development stage. It is intended exclusively for experts who have experience with such software and
23 : solely for the purpose of inspection. All implied warranties of non-infringement, merchantability
24 : and fitness for a particular purpose are hereby disclaimed and excluded.
25 :
26 : Any dispute, controversy or claim arising under or in relation to providing this software shall be
27 : submitted to and settled by the final, binding jurisdiction of the courts of Munich, Germany in
28 : accordance with the laws of the Federal Republic of Germany excluding its conflict of law rules and
29 : the United Nations Convention on Contracts on the International Sales of Goods.
30 :
31 : *******************************************************************************************************/
32 :
33 : #include <stdint.h>
34 : #include "options.h"
35 : #include <math.h>
36 : #include "cnst.h"
37 : #include "prot_fx.h"
38 : #include "ivas_prot_fx.h"
39 : #include "ivas_cnst.h"
40 : #include "ivas_rom_com.h"
41 : #include "ivas_rom_dec.h"
42 : #include "wmc_auto.h"
43 :
44 :
45 : /*-------------------------------------------------------------------------
46 : * Local constants
47 : *------------------------------------------------------------------------*/
48 : #define DOWNMIX_ALPHA_FX 31130 /* Smoothing coefficient alpha */
49 : #define DOWNMIX_ONE_MINUS_ALPHA_FX 1638 /* Smoothing coefficient (1 - alpha) */
50 :
51 : /*-------------------------------------------------------------------------
52 : * ivas_mono_dmx_renderer_open()
53 : *
54 : * Open decoder downmix handle
55 : *-------------------------------------------------------------------------*/
56 :
57 47 : ivas_error ivas_mono_dmx_renderer_open(
58 : Decoder_Struct *st_ivas /* i/o: IVAS decoder structure */
59 : )
60 : {
61 : MONO_DOWNMIX_RENDERER_HANDLE hDownmix;
62 :
63 47 : IF( ( hDownmix = (MONO_DOWNMIX_RENDERER_HANDLE) malloc( sizeof( MONO_DOWNMIX_RENDERER_STRUCT ) ) ) == NULL )
64 : {
65 0 : return ( IVAS_ERROR( IVAS_ERR_FAILED_ALLOC, "Can not allocate memory for downmixing\n" ) );
66 : }
67 :
68 47 : hDownmix->inputEnergy_fx = 0;
69 47 : move16();
70 47 : hDownmix->protoEnergy_fx = 0;
71 47 : move16();
72 47 : hDownmix->Q_inputEner = 0;
73 47 : move16();
74 47 : hDownmix->Q_protoEner = 0;
75 47 : move16();
76 :
77 47 : st_ivas->hMonoDmxRenderer = hDownmix;
78 :
79 47 : return IVAS_ERR_OK;
80 : }
81 :
82 : /*-------------------------------------------------------------------------
83 : * ivas_mono_dmx_renderer_close()
84 : *
85 : * Close decoder downmix handle
86 : *-------------------------------------------------------------------------*/
87 :
88 2455 : void ivas_mono_dmx_renderer_close(
89 : MONO_DOWNMIX_RENDERER_HANDLE *hMonoDmxRenderer /* i/ i/o: Mono downmix structure */
90 : )
91 : {
92 2455 : test();
93 2455 : IF( hMonoDmxRenderer == NULL || *hMonoDmxRenderer == NULL )
94 : {
95 2408 : return;
96 : }
97 :
98 47 : free( *hMonoDmxRenderer );
99 47 : *hMonoDmxRenderer = NULL;
100 :
101 47 : return;
102 : }
103 :
104 : /*-------------------------------------------------------------------------
105 : * ivas_ism_mono_dmx()
106 : *
107 : * Downmix process
108 : *------------------------------------------------------------------------*/
109 5945 : void ivas_ism_mono_dmx_fx(
110 : Decoder_Struct *st_ivas, /* i/o: IVAS decoder structure */
111 : Word32 *output_f_fx[], /* i/o: synthesized core-coder transport channels/mono output Qin = 11/ Qout = 8*/
112 : const Word16 output_frame /* i : output frame length */
113 : )
114 : {
115 : Word16 i, j, numInputChannels;
116 : Word32 proto_signal_fx[L_FRAME48k];
117 : Word16 eq_fx;
118 : Word32 output_shr[L_FRAME48k];
119 : MONO_DOWNMIX_RENDERER_HANDLE hDownmix;
120 : Word16 Q_shift, proto_shift, input_shift, norm_protoEner, norm_inputEner, proto_norm;
121 : Word16 diff_shift, div, div_sqrt;
122 : Word32 protoEner_pre, inputEner_pre;
123 :
124 5945 : numInputChannels = st_ivas->nSCE;
125 5945 : move16();
126 5945 : if ( EQ_32( st_ivas->ivas_format, SBA_ISM_FORMAT ) )
127 : {
128 1000 : numInputChannels = st_ivas->nchan_ism;
129 1000 : move16();
130 : }
131 :
132 5945 : IF( EQ_32( st_ivas->ivas_format, MASA_ISM_FORMAT ) )
133 : {
134 975 : test();
135 975 : IF( EQ_32( st_ivas->ism_mode, ISM_MASA_MODE_MASA_ONE_OBJ ) || EQ_32( st_ivas->ism_mode, ISM_MASA_MODE_PARAM_ONE_OBJ ) )
136 : {
137 595 : numInputChannels = add( st_ivas->nchan_transport, 1 );
138 : }
139 : ELSE
140 : {
141 380 : numInputChannels = add( st_ivas->nchan_transport, st_ivas->nchan_ism );
142 : }
143 : }
144 :
145 5945 : hDownmix = st_ivas->hMonoDmxRenderer;
146 5945 : set32_fx( proto_signal_fx, 0, output_frame );
147 :
148 5945 : Word16 Output_norm = 32;
149 5945 : move16();
150 18100 : FOR( Word16 lp = 0; lp < numInputChannels; lp++ )
151 : {
152 12155 : Word16 norm = L_norm_arr( output_f_fx[lp], output_frame );
153 12155 : Output_norm = s_min( Output_norm, norm );
154 : }
155 5945 : Q_shift = sub( Output_norm, find_guarded_bits_fx( numInputChannels ) );
156 :
157 : /* Compute the Proto Signal */
158 18100 : FOR( i = 0; i < numInputChannels; i++ )
159 : {
160 12155 : v_shr_32( output_f_fx[i], output_shr, output_frame, -Q_shift );
161 12155 : v_add_32( output_shr, proto_signal_fx, proto_signal_fx, output_frame );
162 : }
163 :
164 :
165 5945 : proto_norm = L_norm_arr( proto_signal_fx, output_frame );
166 :
167 5945 : proto_shift = sub( proto_norm, shr( ( add( find_guarded_bits_fx( output_frame ), 1 ) ), 1 ) );
168 5945 : input_shift = sub( Output_norm, shr( ( add( find_guarded_bits_fx( i_mult( output_frame, numInputChannels ) ), 1 ) ), 1 ) );
169 5945 : protoEner_pre = 0;
170 5945 : move32();
171 5945 : inputEner_pre = 0;
172 5945 : move32();
173 4762745 : FOR( i = 0; i < output_frame; i++ )
174 : {
175 4756800 : Word32 proto_sh = L_shl( proto_signal_fx[i], proto_shift );
176 4756800 : protoEner_pre = L_add( protoEner_pre, Mpy_32_32( proto_sh, proto_sh ) );
177 14195200 : FOR( j = 0; j < numInputChannels; j++ )
178 : {
179 9438400 : Word32 output_f_shift = L_shl( output_f_fx[j][i], input_shift );
180 9438400 : inputEner_pre = L_add( inputEner_pre, Mpy_32_32( output_f_shift, output_f_shift ) );
181 : }
182 : }
183 :
184 5945 : hDownmix->inputEnergy_fx = Mpy_32_16_1( hDownmix->inputEnergy_fx, DOWNMIX_ALPHA_FX );
185 5945 : move32();
186 5945 : hDownmix->protoEnergy_fx = Mpy_32_16_1( hDownmix->protoEnergy_fx, DOWNMIX_ALPHA_FX );
187 5945 : move32();
188 :
189 5945 : protoEner_pre = Mpy_32_16_1( protoEner_pre, DOWNMIX_ONE_MINUS_ALPHA_FX );
190 5945 : inputEner_pre = Mpy_32_16_1( inputEner_pre, DOWNMIX_ONE_MINUS_ALPHA_FX );
191 :
192 : /* compute the eq factor */
193 :
194 5945 : IF( hDownmix->protoEnergy_fx == 0 )
195 : {
196 47 : norm_protoEner = add( 31, hDownmix->Q_protoEner );
197 : }
198 : ELSE
199 : {
200 5898 : norm_protoEner = add( norm_l( hDownmix->protoEnergy_fx ), hDownmix->Q_protoEner );
201 : }
202 5945 : IF( hDownmix->inputEnergy_fx == 0 )
203 : {
204 47 : norm_inputEner = add( 31, hDownmix->Q_inputEner );
205 : }
206 : ELSE
207 : {
208 5898 : norm_inputEner = add( norm_l( hDownmix->inputEnergy_fx ), hDownmix->Q_inputEner );
209 : }
210 :
211 5945 : norm_protoEner = sub( s_min( norm_protoEner, sub( shl( add( add( 11, Q_shift ), proto_shift ), 1 ), 31 ) ), 1 );
212 5945 : norm_inputEner = sub( s_min( norm_inputEner, sub( shl( add( 11, input_shift ), 1 ), 31 ) ), 1 );
213 :
214 5945 : hDownmix->protoEnergy_fx = L_shl( hDownmix->protoEnergy_fx, sub( norm_protoEner, hDownmix->Q_protoEner ) );
215 5945 : move32();
216 5945 : hDownmix->inputEnergy_fx = L_shl( hDownmix->inputEnergy_fx, sub( norm_inputEner, hDownmix->Q_inputEner ) );
217 5945 : move32();
218 :
219 5945 : hDownmix->Q_protoEner = norm_protoEner;
220 5945 : move16();
221 5945 : hDownmix->Q_inputEner = norm_inputEner;
222 5945 : move16();
223 :
224 5945 : protoEner_pre = L_shl( protoEner_pre, sub( norm_protoEner, sub( shl( add( add( 11, Q_shift ), proto_shift ), 1 ), 31 ) ) );
225 5945 : inputEner_pre = L_shl( inputEner_pre, sub( norm_inputEner, sub( shl( add( 11, input_shift ), 1 ), 31 ) ) );
226 :
227 5945 : hDownmix->protoEnergy_fx = L_add( hDownmix->protoEnergy_fx, protoEner_pre );
228 5945 : move32();
229 5945 : hDownmix->inputEnergy_fx = L_add( hDownmix->inputEnergy_fx, inputEner_pre );
230 5945 : move32();
231 :
232 5945 : diff_shift = sub( hDownmix->Q_inputEner, hDownmix->Q_protoEner );
233 5945 : IF( diff_shift > 0 )
234 : {
235 298 : hDownmix->inputEnergy_fx = L_shr( hDownmix->inputEnergy_fx, diff_shift );
236 298 : move32();
237 298 : hDownmix->Q_inputEner = sub( hDownmix->Q_inputEner, diff_shift );
238 298 : move16();
239 : }
240 : ELSE
241 : {
242 5647 : hDownmix->protoEnergy_fx = L_shr( hDownmix->protoEnergy_fx, -diff_shift );
243 5647 : move32();
244 5647 : hDownmix->Q_protoEner = add( hDownmix->Q_protoEner, diff_shift );
245 5647 : move16();
246 : }
247 5945 : IF( GE_32( hDownmix->protoEnergy_fx, L_shr( hDownmix->inputEnergy_fx, 2 ) ) )
248 : {
249 5945 : div = BASOP_Util_Divide3232_Scale( hDownmix->inputEnergy_fx, hDownmix->protoEnergy_fx, &diff_shift );
250 5945 : div_sqrt = Sqrt16( div, &diff_shift );
251 5945 : eq_fx = shr( div_sqrt, sub( 3, diff_shift ) );
252 : }
253 : ELSE
254 : {
255 0 : eq_fx = 16384; // 0.5.Q15
256 0 : move16();
257 : }
258 :
259 :
260 : /* equalize the downmix */
261 5945 : v_multc_fixed_16( proto_signal_fx, eq_fx, output_f_fx[0], output_frame );
262 5945 : v_shr_32( output_f_fx[0], output_f_fx[0], output_frame, Q_shift );
263 :
264 5945 : return;
265 : }
266 :
267 : /*-------------------------------------------------------------------------
268 : * ivas_mono_stereo_downmix_mcmasa()
269 : *
270 : * Downmix process in McMASA
271 : *------------------------------------------------------------------------*/
272 :
273 500 : void ivas_mono_stereo_downmix_mcmasa_fx(
274 : Decoder_Struct *st_ivas, /* i/o: IVAS decoder structure */
275 : Word32 *output_f_fx[], /* i/o: synthesized core-coder transport channels/mono or stereo output Q11*/
276 : Word16 output_frame /* i : output frame length per channel */
277 : )
278 : {
279 : Word16 i;
280 :
281 : Word32 dmx_tmp_fx[L_FRAME48k];
282 :
283 500 : set32_fx( dmx_tmp_fx, 0, output_frame );
284 :
285 : /* Dowmix center channel to L and R */
286 500 : test();
287 500 : IF( EQ_16( st_ivas->hDecoderConfig->nchan_out, 2 ) && st_ivas->hOutSetup.separateChannelEnabled )
288 : {
289 200 : v_multc_acc_32_16( output_f_fx[st_ivas->hOutSetup.separateChannelIndex], INV_SQRT2_FX_Q15, output_f_fx[0], output_frame ); // Q11
290 200 : v_multc_acc_32_16( output_f_fx[st_ivas->hOutSetup.separateChannelIndex], INV_SQRT2_FX_Q15, output_f_fx[1], output_frame ); // Q11
291 : }
292 : /* Mono downmix */
293 300 : ELSE IF( EQ_16( st_ivas->hDecoderConfig->nchan_out, 1 ) )
294 : {
295 : /* Downmix L and R to dmx_tmp */
296 900 : FOR( i = 0; i < st_ivas->nchan_transport; i++ )
297 : {
298 600 : v_multc_acc_32_16( output_f_fx[i], INV_SQRT2_FX_Q15, dmx_tmp_fx, output_frame ); // Q11
299 : }
300 : /* Add center channel */
301 300 : IF( st_ivas->hOutSetup.separateChannelEnabled )
302 : {
303 150 : v_add_32( output_f_fx[st_ivas->hOutSetup.separateChannelIndex], dmx_tmp_fx, dmx_tmp_fx, output_frame );
304 : }
305 :
306 : /* Move to output */
307 300 : Copy32( dmx_tmp_fx, output_f_fx[0], output_frame ); // Q11
308 : }
309 :
310 500 : return;
311 : }
312 :
313 :
314 : /*-------------------------------------------------------------------------
315 : * ivas_apply_non_diegetic_panning()
316 : *
317 : * Apply non-diegetic panning
318 : *------------------------------------------------------------------------*/
319 :
320 1500 : void ivas_apply_non_diegetic_panning_fx(
321 : Word32 *input_f_fx, /* i : non-diegetic object */
322 : Word32 *output_f_fx[], /* o: core-coder transport mono channel/stereo output */
323 : const Word16 non_diegetic_pan_gain_fx, /* i : non-diegetic panning gain Q15*/
324 : const Word16 output_frame /* i : output frame length per channel Q11*/
325 : )
326 : {
327 : Word16 pan_left_fx, pan_right_fx;
328 :
329 1500 : pan_left_fx = add( mult( non_diegetic_pan_gain_fx, 16384 ), 16384 ); // 0.5.Q15 = 16384
330 1500 : pan_right_fx = sub( 32767, pan_left_fx );
331 :
332 1500 : v_multc_fixed( input_f_fx, L_shl( L_deposit_l( pan_right_fx ), 16 ), output_f_fx[1], output_frame );
333 1500 : v_multc_fixed( input_f_fx, L_shl( L_deposit_l( pan_left_fx ), 16 ), output_f_fx[0], output_frame );
334 :
335 1500 : return;
336 : }
|