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 : #include <assert.h>
38 : #include <stdint.h>
39 : #include "options.h"
40 : #include <math.h>
41 : #include "prot.h"
42 : #include "cnst.h"
43 : #include "wmc_auto.h"
44 :
45 : /*-------------------------------------------------------------------*
46 : * Local constants
47 : *--------------------------------------------------------------------*/
48 :
49 : #define NB_PULSES_MAX 15
50 :
51 :
52 : /*-------------------------------------------------------------------*
53 : * GetMinimumPosition()
54 : *
55 : * Get the location of the minimum energy in the given signal.
56 : *--------------------------------------------------------------------*/
57 :
58 : /*! r: Index of the position of the minimum energy, that is the position i where filter(x[i-filterLength/2],...,x[i+(filterLength-filterLength/2)-1]) is at maximum. */
59 10014 : static int16_t GetMinimumPosition(
60 : const float *x, /* i : input signal */
61 : const int16_t length, /* i : length of the filter length used for the energy calculation */
62 : int16_t filterLength /* i : length of the filter length used for the energy calculation */
63 : )
64 : {
65 : int16_t iMinEnergyPos, center, i;
66 : float energy;
67 :
68 10014 : filterLength = min( filterLength, length );
69 10014 : center = filterLength / 2;
70 10014 : iMinEnergyPos = center;
71 10014 : if ( filterLength > 0 )
72 : {
73 7203 : energy = 0;
74 7203 : center += 1; /* To avoid adding 1 in the loop */
75 1376376 : for ( i = 0; i < length - filterLength; i++ )
76 : {
77 1369173 : energy -= x[i] * x[i];
78 1369173 : energy += x[i + filterLength] * x[i + filterLength];
79 1369173 : if ( energy < 0 )
80 : {
81 49575 : energy = 0;
82 49575 : iMinEnergyPos = i + center;
83 : }
84 : }
85 : }
86 :
87 10014 : return iMinEnergyPos;
88 : }
89 :
90 :
91 3096 : static void AddSamples(
92 : const float *old_exc,
93 : float *new_exc,
94 : const int16_t L_frame,
95 : const int16_t n_samples_to_add,
96 : const int16_t min_pos[],
97 : const int16_t points_by_pos[],
98 : const int16_t nb_min )
99 : {
100 : float *pt_dest;
101 : const float *pt_src;
102 : int16_t last_min_pos, i, j;
103 :
104 3096 : pt_dest = new_exc;
105 3096 : pt_src = old_exc;
106 3096 : last_min_pos = 0;
107 16722 : for ( i = 0; i < nb_min; i++ )
108 : {
109 : float ftmp;
110 :
111 : /* Copy section */
112 2021742 : for ( j = min_pos[i] - last_min_pos; j > 0; j-- )
113 : {
114 2008116 : *pt_dest++ = *pt_src++;
115 : }
116 :
117 : /* Add some samples */
118 13626 : ftmp = -( *pt_src / 20 );
119 34023 : for ( j = 0; j < points_by_pos[i]; j++ )
120 : {
121 20397 : *pt_dest++ = ftmp;
122 20397 : ftmp = -ftmp;
123 : }
124 :
125 : /* Prepare for the next loop iteration */
126 13626 : last_min_pos = min_pos[i];
127 : }
128 :
129 : /* Copy remaining length */
130 196407 : for ( j = L_frame - n_samples_to_add - last_min_pos; j > 0; j-- )
131 : {
132 193311 : *pt_dest++ = *pt_src++;
133 : }
134 :
135 3096 : return;
136 : }
137 :
138 :
139 1905 : static void RemoveSamples(
140 : const float *old_exc,
141 : float *new_exc,
142 : const int16_t L_frame,
143 : const int16_t n_samples_to_add,
144 : const int16_t min_pos[],
145 : const int16_t points_by_pos[],
146 : const int16_t nb_min )
147 : {
148 : float *pt_dest;
149 : const float *pt_src;
150 : int16_t last_min_pos, i, j;
151 :
152 1905 : pt_dest = new_exc + L_frame;
153 1905 : last_min_pos = L_frame - n_samples_to_add;
154 11262 : for ( i = nb_min - 1; i >= 0; i-- )
155 : {
156 : /* Compute len to copy */
157 : /* Copy section, removing some samples */
158 9357 : pt_src = old_exc + last_min_pos;
159 1309866 : for ( j = last_min_pos - ( min_pos[i] + points_by_pos[i] ); j > 0; j-- )
160 : {
161 1300509 : *--pt_dest = *--pt_src;
162 : }
163 :
164 : /* Prepare for the next loop iteration */
165 9357 : last_min_pos = min_pos[i];
166 : }
167 :
168 : /* Copy remaining length */
169 1905 : pt_src = old_exc + last_min_pos;
170 90132 : for ( j = last_min_pos; j > 0; j-- )
171 : {
172 88227 : *--pt_dest = *--pt_src;
173 : }
174 :
175 1905 : return;
176 : }
177 :
178 :
179 : /*-------------------------------------------------------------------*
180 : * PulseResynchronization()
181 : *
182 : * Resynchronize glottal pulse positions of the signal in src_exc and store it in dst_exc
183 : *--------------------------------------------------------------------*/
184 :
185 5001 : void PulseResynchronization(
186 : const float *src_exc, /* i : Input excitation buffer */
187 : float *dst_exc, /* o : output excitation buffer */
188 : const int16_t nFrameLength, /* i : frame length */
189 : const int16_t nSubframes, /* i : Number of subframes */
190 : const float pitchStart, /* i : Pitch at the end of the last frame */
191 : const float pitchEnd /* i : Pitch at the end of the current frame */
192 : )
193 : {
194 : int16_t T0, i, k;
195 : float pitchDelta, samplesDelta, perCycleDeltaDelta, cycleDelta, freqStart, fractionalLeft, absPitchDiff;
196 : int16_t roundedPitchStart, nSamplesDelta, nSamplesDeltaRemain, iMinPos1, iMinPos[NB_PULSES_MAX + 1], iDeltaSamples[NB_PULSES_MAX + 1], maxDeltaSamples, roundedCycleDelta;
197 :
198 5001 : assert( ( nFrameLength > 0 ) && ( nFrameLength > pitchStart ) && ( nSubframes > 1 ) && ( nSubframes <= 5 ) && ( nFrameLength % nSubframes == 0 ) && ( pitchStart > 0 ) && ( pitchEnd > 0 ) && ( pitchEnd / pitchStart > 1 - 2.0f / ( nSubframes + 1 ) ) && ( src_exc != NULL ) && ( dst_exc != NULL ) && ( src_exc < dst_exc ) );
199 :
200 5001 : pitchDelta = ( pitchEnd - pitchStart ) / nSubframes;
201 5001 : roundedPitchStart = (int16_t) ( pitchStart + 0.5f );
202 5001 : freqStart = 1.0f / roundedPitchStart;
203 :
204 : /* Calculate number of samples to be removed (if negative) or added (if positive) */
205 5001 : samplesDelta = 0.5f * pitchDelta * nFrameLength * ( nSubframes + 1 ) * freqStart;
206 5001 : samplesDelta -= nFrameLength * ( 1.0f - pitchStart * freqStart );
207 :
208 : /* To have enough samples in the buffer of length nFrameLength*(nSubframes+1)/nSubframes, pitchEnd/pitchEnd must be bigger than (nSubframes-1)/(nSubframes+1)=1-2/(nSubframes+1) */
209 : /* Thus nSubframes must be bigger than 1 */
210 5001 : nSamplesDelta = (int16_t) floor( samplesDelta + 0.5f );
211 5001 : nSamplesDeltaRemain = (int16_t) abs( nSamplesDelta );
212 :
213 : /* Find the location of the glottal pulse */
214 5001 : T0 = maximumAbs( src_exc, roundedPitchStart, NULL );
215 :
216 : /* Get the index of the last pulse in the resynchronized frame */
217 5001 : k = (int16_t) ceil( ( nFrameLength - nSamplesDelta - T0 ) * freqStart - 1 );
218 5001 : if ( ( k >= 0 ) && ( k + 1 <= NB_PULSES_MAX ) )
219 : {
220 5001 : absPitchDiff = (float) fabs( roundedPitchStart - pitchEnd );
221 :
222 : /* Calculate the delta of the samples to be added/removed between consecutive cycles */
223 5001 : perCycleDeltaDelta = ( absPitchDiff * ( nFrameLength - samplesDelta ) - (float) fabs( samplesDelta ) * roundedPitchStart ) / ( ( k + 1 ) * ( T0 + 0.5f * k * roundedPitchStart ) );
224 :
225 : /* Calculate the integer number of samples to be added/removed in each pitch cycle */
226 5001 : cycleDelta = max( 0, ( absPitchDiff - ( k + 1 ) * perCycleDeltaDelta ) * T0 * freqStart );
227 5001 : roundedCycleDelta = (int16_t) ( cycleDelta );
228 5001 : iDeltaSamples[0] = roundedCycleDelta;
229 5001 : fractionalLeft = cycleDelta - roundedCycleDelta;
230 5001 : nSamplesDeltaRemain -= roundedCycleDelta;
231 17982 : for ( i = 1; i <= k; i++ )
232 : {
233 12981 : cycleDelta = ( absPitchDiff - ( k + 1 - i ) * perCycleDeltaDelta ) + fractionalLeft;
234 12981 : cycleDelta = max( 0, cycleDelta );
235 :
236 : /* Make sure that the number of samples increases */
237 12981 : if ( roundedCycleDelta > cycleDelta )
238 : {
239 1014 : iDeltaSamples[i] = roundedCycleDelta;
240 1014 : roundedCycleDelta = (int16_t) ( cycleDelta );
241 1014 : iDeltaSamples[i - 1] = roundedCycleDelta;
242 : }
243 : else
244 : {
245 11967 : roundedCycleDelta = (int16_t) ( cycleDelta );
246 11967 : iDeltaSamples[i] = roundedCycleDelta;
247 : }
248 12981 : fractionalLeft = cycleDelta - roundedCycleDelta;
249 12981 : nSamplesDeltaRemain -= roundedCycleDelta;
250 : }
251 :
252 5001 : iDeltaSamples[k + 1] = max( 0, nSamplesDeltaRemain );
253 5001 : maxDeltaSamples = max( iDeltaSamples[k], iDeltaSamples[k + 1] );
254 :
255 : /* Find the location of the minimum energy between the first two pulses */
256 5001 : iMinPos1 = T0 + GetMinimumPosition( src_exc + T0, min( roundedPitchStart, ( nSubframes + 1 ) * nFrameLength / nSubframes - T0 ), maxDeltaSamples );
257 5001 : if ( nSamplesDelta < 0 )
258 : {
259 : /* Find the location of the minimum energy before the first pulse */
260 1905 : if ( iMinPos1 > roundedPitchStart + iDeltaSamples[0] / 2 )
261 : {
262 954 : iMinPos[0] = iMinPos1 - roundedPitchStart - iDeltaSamples[0] / 2;
263 : }
264 : else
265 : {
266 951 : iMinPos[0] = GetMinimumPosition( src_exc, T0, iDeltaSamples[0] ) - iDeltaSamples[0] / 2;
267 : }
268 :
269 : /* Find the location of the minimum energy between the pulses */
270 7452 : for ( i = 1; i <= k; i++ )
271 : {
272 5547 : iMinPos[i] = iMinPos1 + ( i - 1 ) * roundedPitchStart - iDeltaSamples[i] / 2;
273 : }
274 :
275 : /* Find the location of the minimum energy after the last pulse */
276 1905 : if ( iMinPos1 + k * roundedPitchStart + iDeltaSamples[k + 1] - iDeltaSamples[k + 1] / 2 < nFrameLength - nSamplesDelta )
277 : {
278 891 : iMinPos[k + 1] = iMinPos1 + k * roundedPitchStart - iDeltaSamples[k + 1] / 2;
279 : }
280 : else
281 : {
282 1014 : iMinPos[k + 1] = T0 + k * roundedPitchStart + GetMinimumPosition( src_exc + T0 + k * roundedPitchStart, nFrameLength - nSamplesDelta - ( T0 + k * roundedPitchStart ), iDeltaSamples[k + 1] ) - iDeltaSamples[k + 1] / 2;
283 : }
284 :
285 1905 : if ( iMinPos[k + 1] + iDeltaSamples[k + 1] > nFrameLength - nSamplesDelta )
286 : {
287 0 : iDeltaSamples[k] += iMinPos[k + 1] + iDeltaSamples[k + 1] - ( nFrameLength - nSamplesDelta );
288 0 : iDeltaSamples[k + 1] = nFrameLength - nSamplesDelta - iMinPos[k + 1];
289 : }
290 :
291 : /* Remove samples at the given positions */
292 1905 : RemoveSamples( src_exc, dst_exc, nFrameLength, nSamplesDelta, iMinPos, iDeltaSamples, k + 2 );
293 : }
294 : else
295 : {
296 : /* Find the location of the minimum energy before the first pulse */
297 3096 : if ( iMinPos1 > roundedPitchStart )
298 : {
299 1659 : iMinPos[0] = iMinPos1 - roundedPitchStart;
300 : }
301 : else
302 : {
303 1437 : iMinPos[0] = GetMinimumPosition( src_exc, T0, iDeltaSamples[0] );
304 : }
305 :
306 : /* Find the location of the minimum energy between the pulses */
307 10530 : for ( i = 1; i <= k; i++ )
308 : {
309 7434 : iMinPos[i] = iMinPos1;
310 7434 : iMinPos1 += roundedPitchStart;
311 : }
312 :
313 : /* Find the location of the minimum energy after the last pulse */
314 3096 : if ( iMinPos1 < nFrameLength - nSamplesDelta )
315 : {
316 1485 : iMinPos[k + 1] = iMinPos1;
317 : }
318 : else
319 : {
320 1611 : iMinPos[k + 1] = T0 + k * roundedPitchStart + GetMinimumPosition( src_exc + T0 + k * roundedPitchStart, nFrameLength - nSamplesDelta - ( T0 + k * roundedPitchStart ), iDeltaSamples[k + 1] );
321 : }
322 :
323 3096 : if ( iMinPos[k + 1] + iDeltaSamples[k + 1] > nFrameLength - nSamplesDelta )
324 : {
325 57 : iDeltaSamples[k] += iMinPos[k + 1] + iDeltaSamples[k + 1] - ( nFrameLength - nSamplesDelta );
326 57 : iDeltaSamples[k + 1] = nFrameLength - nSamplesDelta - iMinPos[k + 1];
327 : }
328 :
329 : /* Add samples at the given positions */
330 3096 : AddSamples( src_exc, dst_exc, nFrameLength, nSamplesDelta, iMinPos, iDeltaSamples, k + 2 );
331 : }
332 : }
333 :
334 5001 : return;
335 : }
|