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 566 : void scaleSignal16( const Word16 *src, Word16 *dst, Word16 n, Word16 rightShift )
54 : {
55 : Word16 i;
56 :
57 1826166 : FOR( i = 0; i < n; i++ )
58 : {
59 1825600 : dst[i] = shr_r( src[i], rightShift );
60 1825600 : move16();
61 : }
62 566 : }
63 : /* Calculates cross correlation coefficient for template segment. */
64 97200 : 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 97200 : sum = 0;
74 97200 : move32();
75 7873200 : FOR( i = 0; i < corr_len; i += subsampling )
76 : {
77 7776000 : sum = L_mac0( sum, signal[x + i], signal[y + i] );
78 : }
79 :
80 97200 : return sum;
81 : }
82 :
83 : /* Calculates cross correlation coefficient for template segment. */
84 :
85 3608 : 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 3608 : signalX = &signal[x];
98 3608 : signalY = &signal[y];
99 3608 : sumXY = 0;
100 3608 : sumXX = 0;
101 3608 : sumYY = 0;
102 3608 : move32();
103 3608 : move32();
104 3608 : move32();
105 758488 : FOR( i = 0; i < corr_len; i += subsampling )
106 : {
107 754880 : sumXY = L_mac0( sumXY, signalX[i], signalY[i] );
108 754880 : sumXX = L_mac0( sumXX, signalX[i], signalX[i] );
109 754880 : sumYY = L_mac0( sumYY, signalY[i], signalY[i] );
110 : }
111 :
112 3608 : normX = norm_l( sumXX );
113 3608 : sumXX = L_shl( sumXX, normX );
114 3608 : normY = norm_l( sumYY );
115 3608 : sumYY = L_shl( sumYY, normY );
116 3608 : product = L_mult0( extract_h( sumXX ), extract_h( sumYY ) );
117 3608 : normXY = add( normX, normY );
118 3608 : normXY = sub( normXY, 32 );
119 :
120 : /* change norm to factor of 2 */
121 3608 : IF( s_and( normXY, 0x1 ) != 0 )
122 : {
123 1566 : product = L_shr( product, 1 );
124 1566 : normXY = sub( normXY, 1 );
125 : }
126 3608 : sqrtXY = getSqrtWord32( product );
127 3608 : normXY = shr( normXY, 1 );
128 :
129 3608 : IF( sqrtXY != 0 )
130 : {
131 3544 : Flag Overflow = 0;
132 3544 : move32();
133 3544 : normCC = 0;
134 3544 : move16();
135 3544 : cc = BASOP_Util_Divide3216_Scale( sumXY, sqrtXY, &normCC );
136 3544 : normCC = add( normCC, 16 );
137 : /* scale to Q15 with saturation */
138 : BASOP_SATURATE_WARNING_OFF
139 3544 : cc = shl_ro( cc, add( normXY, normCC ), &Overflow );
140 : BASOP_SATURATE_WARNING_ON
141 3544 : *energy = L_shr_r( L_deposit_l( sqrtXY ), normXY );
142 : }
143 : ELSE /* conceal silent frames */
144 : {
145 64 : cc = 0;
146 64 : move16();
147 64 : *energy = L_deposit_l( 1 );
148 64 : move32();
149 : }
150 :
151 3608 : return cc; /* Q15 */
152 : }
153 :
154 27 : Word16 getSignalScaleForCorrelation( Word32 sampleRate )
155 : {
156 : Word16 ret;
157 :
158 27 : IF( LT_32( sampleRate, 16000 ) )
159 : {
160 0 : ret = 2;
161 0 : move16();
162 : }
163 27 : ELSE IF( GE_32( sampleRate, 32000 ) )
164 : {
165 24 : ret = 4;
166 24 : move16();
167 : }
168 : ELSE
169 : {
170 3 : ret = 3;
171 3 : move16();
172 : }
173 :
174 27 : return ret;
175 : }
176 :
177 0 : Word32 cross_correlation_self_fx( const Word16 *signal,
178 : Word16 x,
179 : Word16 y,
180 : Word16 corr_len )
181 : {
182 : Word32 sum;
183 : Word16 i;
184 :
185 0 : sum = 0;
186 0 : move32();
187 0 : FOR( i = 0; i < corr_len; i++ )
188 : {
189 0 : sum = L_mac0( sum, signal[x + i], signal[y + i] );
190 : }
191 :
192 0 : return sum;
193 : }
194 :
195 0 : Word8 isSilence_fx( const Word16 *signal, Word16 len, Word16 segments )
196 : {
197 : Word16 i, j, samplesPerSegment;
198 : Word32 energy, maxEnergy;
199 : Word8 ret;
200 :
201 0 : assert( len > 0 );
202 0 : assert( segments > 0 );
203 :
204 : /* Every segment is checked using the following formula:
205 : * 10 * log10(sum_i(signal[i]*signal[i]))) > -65
206 : * For simplification/complexity, this is replaced by:
207 : * 20 * log10(sum_i(abs(signal[i]))) > -65
208 : */
209 :
210 0 : ret = 1;
211 0 : move16();
212 0 : energy = 0;
213 0 : move32();
214 0 : samplesPerSegment = idiv1616U( len, segments );
215 : /* calculate maxEnergy with factor 2 to reduce rounding error */
216 0 : maxEnergy = L_mult0( samplesPerSegment, 37 ); /* 37 = 2 * exp10(-65.0 / 20) * 32768 */
217 0 : maxEnergy = L_shr( maxEnergy, 1 );
218 0 : j = samplesPerSegment;
219 0 : move16();
220 : /* check all but last segment */
221 0 : FOR( i = 0; i < len; i++ )
222 : {
223 : /* division by 32768 is done later */
224 0 : energy = L_add( energy, L_abs( L_deposit_l( signal[i] ) ) );
225 0 : IF( EQ_16( i, j ) )
226 : {
227 : /* check energy of current segment */
228 : /* 20 * log10(energy / 32768 / samplesPerSegment) > -65
229 : * => energy > samplesPerSegment * 10 ^ (-65 / 20) * 32768 */
230 0 : IF( GT_32( energy, maxEnergy ) )
231 : {
232 0 : ret = 0;
233 0 : move16();
234 0 : BREAK;
235 : }
236 0 : energy = 0;
237 0 : move32();
238 0 : j = add( j, samplesPerSegment );
239 : }
240 : }
241 : /* check last segment */
242 0 : if ( GT_32( energy, maxEnergy ) )
243 : {
244 0 : ret = 0;
245 0 : move16();
246 : }
247 0 : return ret;
248 : }
249 :
250 566 : Word8 isSilence_ivas_fx( const Word16 *signal, Word16 q_sig, Word16 len, Word16 segments )
251 : {
252 : Word16 i, j, samplesPerSegment;
253 : Word64 energy, maxEnergy;
254 566 : Word16 sig_shift = shl( q_sig, 1 );
255 :
256 566 : assert( len > 0 );
257 566 : assert( segments > 0 );
258 :
259 : /* Every segment is checked using the following formula:
260 : * 10 * log10(sum_i(signal[i] / 32768.0 *signal[i] / 32768.0)) / samples_per_segment) > -65
261 : * For simplification/complexity, this is replaced by:
262 : * sum_i(signal[i] / 32768.0 * signal[i] / 32768.0) / samples_per_segment > 10^(-65 / 10)
263 : * sum_i(signal[i] * signal[i]) > 10^(-65 / 10) * 32768.0 * 32768.0 * samples_per_segment
264 : */
265 :
266 566 : energy = 0;
267 566 : move64();
268 566 : samplesPerSegment = idiv1616U( len, segments );
269 566 : maxEnergy = W_shl( W_mac0_16_16( 0, samplesPerSegment, 340 ), sig_shift ); /* 340 = 10^(-65.0 / 10) * 32768 * 32768.0 */
270 566 : j = samplesPerSegment;
271 566 : move16();
272 : /* check all but last segment */
273 1144 : FOR( i = 0; i < len; i++ )
274 : {
275 : /* division by 32768 is done later */
276 1144 : energy = W_mac0_16_16( energy, signal[i], signal[i] );
277 : /* check energy of current segment
278 : * => energy > samplesPerSegment * 10 ^ (-65 / 10) * 32768 * 32768.0*/
279 1144 : IF( GT_64( energy, maxEnergy ) )
280 : {
281 566 : return 0;
282 : }
283 578 : IF( EQ_16( i, j ) )
284 : {
285 3 : energy = 0;
286 3 : move64();
287 3 : j = add( j, samplesPerSegment );
288 : }
289 : }
290 :
291 0 : return 1;
292 : }
|