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 */
49 : #define MONO_DOWNMIX_RENDERER_MAX_INPUT_CHANS 4
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 2209 : void ivas_mono_dmx_renderer_close(
89 : MONO_DOWNMIX_RENDERER_HANDLE *hMonoDmxRenderer /* i/ i/o: Mono downmix structure */
90 : )
91 : {
92 2209 : test();
93 2209 : IF( hMonoDmxRenderer == NULL || *hMonoDmxRenderer == NULL )
94 : {
95 2162 : return;
96 : }
97 :
98 47 : free( *hMonoDmxRenderer );
99 47 : *hMonoDmxRenderer = NULL;
100 :
101 47 : return;
102 : }
103 :
104 : /*-------------------------------------------------------------------------
105 : * ivas_mono_downmix_render_passive()
106 : *
107 : * Downmix process
108 : *------------------------------------------------------------------------*/
109 5945 : void ivas_mono_downmix_render_passive_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 5945 : numInputChannels = st_ivas->nSCE;
124 5945 : move16();
125 5945 : if ( EQ_32( st_ivas->ivas_format, SBA_ISM_FORMAT ) )
126 : {
127 1000 : numInputChannels = st_ivas->nchan_ism;
128 1000 : move16();
129 : }
130 :
131 5945 : IF( EQ_32( st_ivas->ivas_format, MASA_ISM_FORMAT ) )
132 : {
133 975 : test();
134 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 ) )
135 : {
136 595 : numInputChannels = add( st_ivas->nchan_transport, 1 );
137 : }
138 : ELSE
139 : {
140 380 : numInputChannels = add( st_ivas->nchan_transport, st_ivas->nchan_ism );
141 : }
142 : }
143 :
144 5945 : hDownmix = st_ivas->hMonoDmxRenderer;
145 5945 : set32_fx( proto_signal_fx, 0, output_frame );
146 :
147 5945 : Word16 Output_norm = 32;
148 5945 : move16();
149 18100 : FOR( Word16 lp = 0; lp < numInputChannels; lp++ )
150 : {
151 12155 : Word16 norm = L_norm_arr( output_f_fx[lp], output_frame );
152 12155 : Output_norm = s_min( Output_norm, norm );
153 : }
154 5945 : Q_shift = sub( Output_norm, find_guarded_bits_fx( numInputChannels ) );
155 :
156 : /* Compute the Proto Signal */
157 18100 : FOR( i = 0; i < numInputChannels; i++ )
158 : {
159 12155 : v_shr_32( output_f_fx[i], output_shr, output_frame, -Q_shift );
160 12155 : v_add_32( output_shr, proto_signal_fx, proto_signal_fx, output_frame );
161 : }
162 :
163 : /* compute the input energy, proto energy after smoothing */
164 5945 : hDownmix->inputEnergy_fx = Mpy_32_16_1( hDownmix->inputEnergy_fx, DOWNMIX_ALPHA_FX );
165 5945 : move32();
166 5945 : hDownmix->protoEnergy_fx = Mpy_32_16_1( hDownmix->protoEnergy_fx, DOWNMIX_ALPHA_FX );
167 5945 : move32();
168 :
169 5945 : proto_norm = L_norm_arr( proto_signal_fx, output_frame );
170 :
171 5945 : proto_shift = sub( proto_norm, shr( ( add( find_guarded_bits_fx( output_frame ), 1 ) ), 1 ) );
172 5945 : input_shift = sub( Output_norm, shr( ( add( find_guarded_bits_fx( i_mult( output_frame, numInputChannels ) ), 1 ) ), 1 ) );
173 5945 : protoEner_pre = 0;
174 5945 : move32();
175 5945 : inputEner_pre = 0;
176 5945 : move32();
177 4762745 : FOR( i = 0; i < output_frame; i++ )
178 : {
179 4756800 : Word32 proto_sh = L_shl( proto_signal_fx[i], proto_shift );
180 4756800 : protoEner_pre = L_add( protoEner_pre, Mpy_32_32( proto_sh, proto_sh ) );
181 14195200 : FOR( j = 0; j < numInputChannels; j++ )
182 : {
183 9438400 : Word32 output_f_shift = L_shl( output_f_fx[j][i], input_shift );
184 9438400 : inputEner_pre = L_add( inputEner_pre, Mpy_32_32( output_f_shift, output_f_shift ) );
185 : }
186 : }
187 :
188 : /* compute the eq factor */
189 :
190 5945 : IF( hDownmix->protoEnergy_fx == 0 )
191 : {
192 47 : norm_protoEner = add( 31, hDownmix->Q_protoEner );
193 : }
194 : ELSE
195 : {
196 5898 : norm_protoEner = add( norm_l( hDownmix->protoEnergy_fx ), hDownmix->Q_protoEner );
197 : }
198 5945 : IF( hDownmix->inputEnergy_fx == 0 )
199 : {
200 47 : norm_inputEner = add( 31, hDownmix->Q_inputEner );
201 : }
202 : ELSE
203 : {
204 5898 : norm_inputEner = add( norm_l( hDownmix->inputEnergy_fx ), hDownmix->Q_inputEner );
205 : }
206 :
207 5945 : norm_protoEner = sub( s_min( norm_protoEner, sub( shl( add( add( 11, Q_shift ), proto_shift ), 1 ), 31 ) ), 1 );
208 5945 : norm_inputEner = sub( s_min( norm_inputEner, sub( shl( add( 11, input_shift ), 1 ), 31 ) ), 1 );
209 :
210 5945 : hDownmix->protoEnergy_fx = L_shl( hDownmix->protoEnergy_fx, sub( norm_protoEner, hDownmix->Q_protoEner ) );
211 5945 : move32();
212 5945 : hDownmix->inputEnergy_fx = L_shl( hDownmix->inputEnergy_fx, sub( norm_inputEner, hDownmix->Q_inputEner ) );
213 5945 : move32();
214 :
215 5945 : hDownmix->Q_protoEner = norm_protoEner;
216 5945 : move16();
217 5945 : hDownmix->Q_inputEner = norm_inputEner;
218 5945 : move16();
219 :
220 5945 : protoEner_pre = L_shl( protoEner_pre, sub( norm_protoEner, sub( shl( add( add( 11, Q_shift ), proto_shift ), 1 ), 31 ) ) );
221 5945 : inputEner_pre = L_shl( inputEner_pre, sub( norm_inputEner, sub( shl( add( 11, input_shift ), 1 ), 31 ) ) );
222 :
223 5945 : hDownmix->protoEnergy_fx = L_add( hDownmix->protoEnergy_fx, protoEner_pre );
224 5945 : move32();
225 5945 : hDownmix->inputEnergy_fx = L_add( hDownmix->inputEnergy_fx, inputEner_pre );
226 5945 : move32();
227 :
228 5945 : diff_shift = sub( hDownmix->Q_inputEner, hDownmix->Q_protoEner );
229 5945 : IF( diff_shift > 0 )
230 : {
231 730 : hDownmix->inputEnergy_fx = L_shr( hDownmix->inputEnergy_fx, diff_shift );
232 730 : move32();
233 730 : hDownmix->Q_inputEner = sub( hDownmix->Q_inputEner, diff_shift );
234 730 : move16();
235 : }
236 : ELSE
237 : {
238 5215 : hDownmix->protoEnergy_fx = L_shr( hDownmix->protoEnergy_fx, -diff_shift );
239 5215 : move32();
240 5215 : hDownmix->Q_protoEner = add( hDownmix->Q_protoEner, diff_shift );
241 5215 : move16();
242 : }
243 5945 : IF( GE_32( hDownmix->protoEnergy_fx, L_shr( hDownmix->inputEnergy_fx, 2 ) ) )
244 : {
245 5945 : div = BASOP_Util_Divide3232_Scale( hDownmix->inputEnergy_fx, hDownmix->protoEnergy_fx, &diff_shift );
246 5945 : div_sqrt = Sqrt16( div, &diff_shift );
247 5945 : eq_fx = shr( div_sqrt, sub( 3, diff_shift ) );
248 : }
249 : ELSE
250 : {
251 0 : eq_fx = 16384; // 0.5.Q15
252 0 : move16();
253 : }
254 :
255 :
256 : /* equalize the downmix */
257 5945 : v_multc_fixed_16( proto_signal_fx, eq_fx, output_f_fx[0], output_frame );
258 5945 : v_shr_32( output_f_fx[0], output_f_fx[0], output_frame, Q_shift );
259 :
260 5945 : return;
261 : }
262 :
263 : /*-------------------------------------------------------------------------
264 : * ivas_mono_stereo_downmix_mcmasa()
265 : *
266 : * Downmix process in McMASA
267 : *------------------------------------------------------------------------*/
268 :
269 500 : void ivas_mono_stereo_downmix_mcmasa_fx(
270 : Decoder_Struct *st_ivas, /* i/o: IVAS decoder structure */
271 : Word32 *output_f_fx[], /* i/o: synthesized core-coder transport channels/mono or stereo output Q11*/
272 : Word16 output_frame /* i : output frame length per channel */
273 : )
274 : {
275 : Word16 i;
276 :
277 : Word32 dmx_tmp_fx[L_FRAME48k];
278 :
279 500 : set32_fx( dmx_tmp_fx, 0, output_frame );
280 :
281 : /* Dowmix center channel to L and R */
282 500 : test();
283 500 : IF( EQ_16( st_ivas->hDecoderConfig->nchan_out, 2 ) && st_ivas->hOutSetup.separateChannelEnabled )
284 : {
285 200 : v_multc_acc_32_16( output_f_fx[st_ivas->hOutSetup.separateChannelIndex], INV_SQRT2_FX_Q15, output_f_fx[0], output_frame ); // Q11
286 200 : v_multc_acc_32_16( output_f_fx[st_ivas->hOutSetup.separateChannelIndex], INV_SQRT2_FX_Q15, output_f_fx[1], output_frame ); // Q11
287 : }
288 : /* Mono downmix */
289 300 : ELSE IF( EQ_16( st_ivas->hDecoderConfig->nchan_out, 1 ) )
290 : {
291 : /* Downmix L and R to dmx_tmp */
292 900 : FOR( i = 0; i < st_ivas->nchan_transport; i++ )
293 : {
294 600 : v_multc_acc_32_16( output_f_fx[i], INV_SQRT2_FX_Q15, dmx_tmp_fx, output_frame ); // Q11
295 : }
296 : /* Add center channel */
297 300 : IF( st_ivas->hOutSetup.separateChannelEnabled )
298 : {
299 150 : v_add_32( output_f_fx[st_ivas->hOutSetup.separateChannelIndex], dmx_tmp_fx, dmx_tmp_fx, output_frame );
300 : }
301 :
302 : /* Move to output */
303 300 : Copy32( dmx_tmp_fx, output_f_fx[0], output_frame ); // Q11
304 : }
305 :
306 500 : return;
307 : }
308 :
309 :
310 : /*-------------------------------------------------------------------------
311 : * ivas_apply_non_diegetic_panning()
312 : *
313 : * Apply non-diegetic panning
314 : *------------------------------------------------------------------------*/
315 :
316 1500 : void ivas_apply_non_diegetic_panning_fx(
317 : Word32 *output_f_fx[], /* i/o: core-coder transport mono channel/stereo output */
318 : const Word16 non_diegetic_pan_gain_fx, /* i : non-diegetic panning gain Q15*/
319 : const Word16 output_frame /* i : output frame length per channel Q11*/
320 : )
321 : {
322 : Word16 pan_left_fx, pan_right_fx;
323 :
324 1500 : pan_left_fx = add( mult( non_diegetic_pan_gain_fx, 16384 ), 16384 ); // 0.5.Q15 = 16384
325 1500 : pan_right_fx = sub( 32767, pan_left_fx );
326 :
327 1500 : v_multc_fixed( output_f_fx[0], L_shl( L_deposit_l( pan_right_fx ), 16 ), output_f_fx[1], output_frame );
328 1500 : v_multc_fixed( output_f_fx[0], L_shl( L_deposit_l( pan_left_fx ), 16 ), output_f_fx[0], output_frame );
329 :
330 1500 : return;
331 : }
|