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 : /*====================================================================================
34 : EVS Codec 3GPP TS26.443 Nov 04, 2021. Version 12.14.0 / 13.10.0 / 14.6.0 / 15.4.0 / 16.3.0
35 : ====================================================================================*/
36 :
37 : /*! @file jbm_pcmdsp_similarityestimation.c Algorithms for correlation and similarity estimation. */
38 :
39 : /* system headers */
40 : #include <stdlib.h>
41 : #include <math.h>
42 : #include <stdint.h>
43 : #include <assert.h>
44 : #include "options.h"
45 : #include "wmc_auto.h"
46 : #include "basop_util.h"
47 :
48 : /* local headers */
49 : #include "jbm_pcmdsp_similarityestimation.h"
50 :
51 :
52 : /* Calculates cross correlation coefficient for template segment. */
53 454 : void scaleSignal16( const Word16 *src, Word16 *dst, Word16 n, Word16 rightShift )
54 : {
55 : Word16 i;
56 :
57 1681734 : FOR( i = 0; i < n; i++ )
58 : {
59 1681280 : dst[i] = shr_r( src[i], rightShift );
60 1681280 : move16();
61 : }
62 454 : }
63 : /* Calculates cross correlation coefficient for template segment. */
64 82560 : Word32 cross_correlation_subsampled_self_fx( const Word16 *signal,
65 : Word16 x,
66 : Word16 y,
67 : Word16 corr_len,
68 : Word16 subsampling )
69 : {
70 : Word32 sum;
71 : Word16 i;
72 :
73 82560 : sum = 0;
74 82560 : move32();
75 6687360 : FOR( i = 0; i < corr_len; i += subsampling )
76 : {
77 6604800 : sum = L_mac0( sum, signal[x + i], signal[y + i] );
78 : }
79 :
80 82560 : return sum;
81 : }
82 :
83 : /* Calculates cross correlation coefficient for template segment. */
84 :
85 3251 : Word16 normalized_cross_correlation_self_fx( const Word16 *signal,
86 : Word16 x,
87 : Word16 y,
88 : Word16 corr_len,
89 : Word16 subsampling,
90 : Word32 *energy )
91 : {
92 : const Word16 *signalX, *signalY;
93 : Word32 sumXY, sumXX, sumYY, product;
94 : Word16 sqrtXY, cc;
95 : Word16 i, normX, normY, normXY, normCC;
96 :
97 3251 : signalX = &signal[x];
98 3251 : signalY = &signal[y];
99 3251 : sumXY = 0;
100 3251 : sumXX = 0;
101 3251 : sumYY = 0;
102 3251 : move32();
103 3251 : move32();
104 3251 : move32();
105 673411 : FOR( i = 0; i < corr_len; i += subsampling )
106 : {
107 670160 : sumXY = L_mac0( sumXY, signalX[i], signalY[i] );
108 670160 : sumXX = L_mac0( sumXX, signalX[i], signalX[i] );
109 670160 : sumYY = L_mac0( sumYY, signalY[i], signalY[i] );
110 : }
111 :
112 3251 : normX = norm_l( sumXX );
113 3251 : sumXX = L_shl( sumXX, normX );
114 3251 : normY = norm_l( sumYY );
115 3251 : sumYY = L_shl( sumYY, normY );
116 3251 : product = L_shr( L_mult0( extract_h( sumXX ), extract_h( sumYY ) ), 1 );
117 3251 : normXY = add( normX, normY );
118 3251 : normXY = sub( normXY, 32 + 1 );
119 :
120 : /* change norm to factor of 2 */
121 3251 : IF( s_and( normXY, 0x1 ) != 0 )
122 : {
123 1831 : product = L_shr( product, 1 );
124 1831 : normXY = sub( normXY, 1 );
125 : }
126 3251 : sqrtXY = getSqrtWord32( product );
127 3251 : normXY = shr( normXY, 1 );
128 :
129 3251 : IF( sqrtXY != 0 )
130 : {
131 3189 : move32();
132 3189 : normCC = 0;
133 3189 : move16();
134 3189 : cc = BASOP_Util_Divide3216_Scale( sumXY, sqrtXY, &normCC );
135 3189 : normCC = add( normCC, 16 );
136 : /* scale to Q15 with saturation */
137 : BASOP_SATURATE_WARNING_OFF
138 3189 : cc = shr_r_sat( cc, negate( add( normXY, normCC ) ) );
139 : BASOP_SATURATE_WARNING_ON
140 3189 : *energy = L_shr_r( L_deposit_l( sqrtXY ), normXY );
141 : }
142 : ELSE /* conceal silent frames */
143 : {
144 62 : cc = 0;
145 62 : move16();
146 62 : *energy = L_deposit_l( 1 );
147 62 : move32();
148 : }
149 :
150 3251 : return cc; /* Q15 */
151 : }
152 :
153 28 : Word16 getSignalScaleForCorrelation( Word32 sampleRate )
154 : {
155 : Word16 ret;
156 :
157 28 : IF( LT_32( sampleRate, 16000 ) )
158 : {
159 0 : ret = 2;
160 0 : move16();
161 : }
162 28 : ELSE IF( GE_32( sampleRate, 32000 ) )
163 : {
164 25 : ret = 4;
165 25 : move16();
166 : }
167 : ELSE
168 : {
169 3 : ret = 3;
170 3 : move16();
171 : }
172 :
173 28 : return ret;
174 : }
175 :
176 0 : Word32 cross_correlation_self_fx( const Word16 *signal,
177 : Word16 x,
178 : Word16 y,
179 : Word16 corr_len )
180 : {
181 : Word32 sum;
182 : Word16 i;
183 :
184 0 : sum = 0;
185 0 : move32();
186 0 : FOR( i = 0; i < corr_len; i++ )
187 : {
188 0 : sum = L_mac0( sum, signal[x + i], signal[y + i] );
189 : }
190 :
191 0 : return sum;
192 : }
193 :
194 0 : Word8 isSilence_fx( const Word16 *signal, Word16 len, Word16 segments )
195 : {
196 : Word16 i, j, samplesPerSegment;
197 : Word32 energy, maxEnergy;
198 : Word8 ret;
199 :
200 0 : assert( len > 0 );
201 0 : assert( segments > 0 );
202 :
203 : /* Every segment is checked using the following formula:
204 : * 10 * log10(sum_i(signal[i]*signal[i]))) > -65
205 : * For simplification/complexity, this is replaced by:
206 : * 20 * log10(sum_i(abs(signal[i]))) > -65
207 : */
208 :
209 0 : ret = 1;
210 0 : move16();
211 0 : energy = 0;
212 0 : move32();
213 0 : samplesPerSegment = idiv1616U( len, segments );
214 : /* calculate maxEnergy with factor 2 to reduce rounding error */
215 0 : maxEnergy = L_mult0( samplesPerSegment, 37 ); /* 37 = 2 * exp10(-65.0 / 20) * 32768 */
216 0 : maxEnergy = L_shr( maxEnergy, 1 );
217 0 : j = samplesPerSegment;
218 0 : move16();
219 : /* check all but last segment */
220 0 : FOR( i = 0; i < len; i++ )
221 : {
222 : /* division by 32768 is done later */
223 0 : energy = L_add( energy, L_abs( L_deposit_l( signal[i] ) ) );
224 0 : IF( EQ_16( i, j ) )
225 : {
226 : /* check energy of current segment */
227 : /* 20 * log10(energy / 32768 / samplesPerSegment) > -65
228 : * => energy > samplesPerSegment * 10 ^ (-65 / 20) * 32768 */
229 0 : IF( GT_32( energy, maxEnergy ) )
230 : {
231 0 : ret = 0;
232 0 : move16();
233 0 : BREAK;
234 : }
235 0 : energy = 0;
236 0 : move32();
237 0 : j = add( j, samplesPerSegment );
238 : }
239 : }
240 : /* check last segment */
241 0 : if ( GT_32( energy, maxEnergy ) )
242 : {
243 0 : ret = 0;
244 0 : move16();
245 : }
246 0 : return ret;
247 : }
248 :
249 454 : Word8 isSilence_ivas_fx( const Word16 *signal, Word16 q_sig, Word16 len, Word16 segments )
250 : {
251 : Word16 i, j, samplesPerSegment;
252 : Word64 energy, maxEnergy;
253 454 : Word16 sig_shift = shl( q_sig, 1 );
254 :
255 454 : assert( len > 0 );
256 454 : assert( segments > 0 );
257 :
258 : /* Every segment is checked using the following formula:
259 : * 10 * log10(sum_i(signal[i] / 32768.0 *signal[i] / 32768.0)) / samples_per_segment) > -65
260 : * For simplification/complexity, this is replaced by:
261 : * sum_i(signal[i] / 32768.0 * signal[i] / 32768.0) / samples_per_segment > 10^(-65 / 10)
262 : * sum_i(signal[i] * signal[i]) > 10^(-65 / 10) * 32768.0 * 32768.0 * samples_per_segment
263 : */
264 :
265 454 : energy = 0;
266 454 : move64();
267 454 : samplesPerSegment = idiv1616U( len, segments );
268 454 : maxEnergy = W_shl( W_mac0_16_16( 0, samplesPerSegment, 340 ), sig_shift ); /* 340 = 10^(-65.0 / 10) * 32768 * 32768.0 */
269 454 : j = samplesPerSegment;
270 454 : move16();
271 : /* check all but last segment */
272 613 : FOR( i = 0; i < len; i++ )
273 : {
274 : /* division by 32768 is done later */
275 613 : energy = W_mac0_16_16( energy, signal[i], signal[i] );
276 : /* check energy of current segment
277 : * => energy > samplesPerSegment * 10 ^ (-65 / 10) * 32768 * 32768.0*/
278 613 : IF( GT_64( energy, maxEnergy ) )
279 : {
280 454 : return 0;
281 : }
282 159 : IF( EQ_16( i, j ) )
283 : {
284 0 : energy = 0;
285 0 : move64();
286 0 : j = add( j, samplesPerSegment );
287 : }
288 : }
289 :
290 0 : return 1;
291 : }
|