xref: /aosp_15_r20/external/libopus/silk/float/encode_frame_FLP.c (revision a58d3d2adb790c104798cd88c8a3aff4fa8b82cc)
1 /***********************************************************************
2 Copyright (c) 2006-2011, Skype Limited. All rights reserved.
3 Redistribution and use in source and binary forms, with or without
4 modification, are permitted provided that the following conditions
5 are met:
6 - Redistributions of source code must retain the above copyright notice,
7 this list of conditions and the following disclaimer.
8 - Redistributions in binary form must reproduce the above copyright
9 notice, this list of conditions and the following disclaimer in the
10 documentation and/or other materials provided with the distribution.
11 - Neither the name of Internet Society, IETF or IETF Trust, nor the
12 names of specific contributors, may be used to endorse or promote
13 products derived from this software without specific prior written
14 permission.
15 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
19 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 POSSIBILITY OF SUCH DAMAGE.
26 ***********************************************************************/
27 
28 #ifdef HAVE_CONFIG_H
29 #include "config.h"
30 #endif
31 
32 #include <stdlib.h>
33 #include "main_FLP.h"
34 #include "tuning_parameters.h"
35 
36 /* Low Bitrate Redundancy (LBRR) encoding. Reuse all parameters but encode with lower bitrate */
37 static OPUS_INLINE void silk_LBRR_encode_FLP(
38     silk_encoder_state_FLP          *psEnc,                             /* I/O  Encoder state FLP                           */
39     silk_encoder_control_FLP        *psEncCtrl,                         /* I/O  Encoder control FLP                         */
40     const silk_float                xfw[],                              /* I    Input signal                                */
41     opus_int                        condCoding                          /* I    The type of conditional coding used so far for this frame */
42 );
43 
silk_encode_do_VAD_FLP(silk_encoder_state_FLP * psEnc,opus_int activity)44 void silk_encode_do_VAD_FLP(
45     silk_encoder_state_FLP          *psEnc,                             /* I/O  Encoder state FLP                           */
46     opus_int                        activity                            /* I    Decision of Opus voice activity detector    */
47 )
48 {
49     const opus_int activity_threshold = SILK_FIX_CONST( SPEECH_ACTIVITY_DTX_THRES, 8 );
50 
51     /****************************/
52     /* Voice Activity Detection */
53     /****************************/
54     silk_VAD_GetSA_Q8( &psEnc->sCmn, psEnc->sCmn.inputBuf + 1, psEnc->sCmn.arch );
55     /* If Opus VAD is inactive and Silk VAD is active: lower Silk VAD to just under the threshold */
56     if( activity == VAD_NO_ACTIVITY && psEnc->sCmn.speech_activity_Q8 >= activity_threshold ) {
57         psEnc->sCmn.speech_activity_Q8 = activity_threshold - 1;
58     }
59 
60     /**************************************************/
61     /* Convert speech activity into VAD and DTX flags */
62     /**************************************************/
63     if( psEnc->sCmn.speech_activity_Q8 < activity_threshold ) {
64         psEnc->sCmn.indices.signalType = TYPE_NO_VOICE_ACTIVITY;
65         psEnc->sCmn.noSpeechCounter++;
66         if( psEnc->sCmn.noSpeechCounter <= NB_SPEECH_FRAMES_BEFORE_DTX ) {
67             psEnc->sCmn.inDTX = 0;
68         } else if( psEnc->sCmn.noSpeechCounter > MAX_CONSECUTIVE_DTX + NB_SPEECH_FRAMES_BEFORE_DTX ) {
69             psEnc->sCmn.noSpeechCounter = NB_SPEECH_FRAMES_BEFORE_DTX;
70             psEnc->sCmn.inDTX           = 0;
71         }
72         psEnc->sCmn.VAD_flags[ psEnc->sCmn.nFramesEncoded ] = 0;
73     } else {
74         psEnc->sCmn.noSpeechCounter    = 0;
75         psEnc->sCmn.inDTX              = 0;
76         psEnc->sCmn.indices.signalType = TYPE_UNVOICED;
77         psEnc->sCmn.VAD_flags[ psEnc->sCmn.nFramesEncoded ] = 1;
78     }
79 }
80 
81 /****************/
82 /* Encode frame */
83 /****************/
silk_encode_frame_FLP(silk_encoder_state_FLP * psEnc,opus_int32 * pnBytesOut,ec_enc * psRangeEnc,opus_int condCoding,opus_int maxBits,opus_int useCBR)84 opus_int silk_encode_frame_FLP(
85     silk_encoder_state_FLP          *psEnc,                             /* I/O  Encoder state FLP                           */
86     opus_int32                      *pnBytesOut,                        /* O    Number of payload bytes;                    */
87     ec_enc                          *psRangeEnc,                        /* I/O  compressor data structure                   */
88     opus_int                        condCoding,                         /* I    The type of conditional coding to use       */
89     opus_int                        maxBits,                            /* I    If > 0: maximum number of output bits       */
90     opus_int                        useCBR                              /* I    Flag to force constant-bitrate operation    */
91 )
92 {
93     silk_encoder_control_FLP sEncCtrl;
94     opus_int     i, iter, maxIter, found_upper, found_lower, ret = 0;
95     silk_float   *x_frame, *res_pitch_frame;
96     silk_float   res_pitch[ 2 * MAX_FRAME_LENGTH + LA_PITCH_MAX ];
97     ec_enc       sRangeEnc_copy, sRangeEnc_copy2;
98     silk_nsq_state sNSQ_copy, sNSQ_copy2;
99     opus_int32   seed_copy, nBits, nBits_lower, nBits_upper, gainMult_lower, gainMult_upper;
100     opus_int32   gainsID, gainsID_lower, gainsID_upper;
101     opus_int16   gainMult_Q8;
102     opus_int16   ec_prevLagIndex_copy;
103     opus_int     ec_prevSignalType_copy;
104     opus_int8    LastGainIndex_copy2;
105     opus_int32   pGains_Q16[ MAX_NB_SUBFR ];
106     opus_uint8   ec_buf_copy[ 1275 ];
107     opus_int     gain_lock[ MAX_NB_SUBFR ] = {0};
108     opus_int16   best_gain_mult[ MAX_NB_SUBFR ];
109     opus_int     best_sum[ MAX_NB_SUBFR ];
110     opus_int     bits_margin;
111 
112     /* For CBR, 5 bits below budget is close enough. For VBR, allow up to 25% below the cap if we initially busted the budget. */
113     bits_margin = useCBR ? 5 : maxBits/4;
114     /* This is totally unnecessary but many compilers (including gcc) are too dumb to realise it */
115     LastGainIndex_copy2 = nBits_lower = nBits_upper = gainMult_lower = gainMult_upper = 0;
116 
117     psEnc->sCmn.indices.Seed = psEnc->sCmn.frameCounter++ & 3;
118 
119     /**************************************************************/
120     /* Set up Input Pointers, and insert frame in input buffer    */
121     /**************************************************************/
122     /* pointers aligned with start of frame to encode */
123     x_frame         = psEnc->x_buf + psEnc->sCmn.ltp_mem_length;    /* start of frame to encode */
124     res_pitch_frame = res_pitch    + psEnc->sCmn.ltp_mem_length;    /* start of pitch LPC residual frame */
125 
126     /***************************************/
127     /* Ensure smooth bandwidth transitions */
128     /***************************************/
129     silk_LP_variable_cutoff( &psEnc->sCmn.sLP, psEnc->sCmn.inputBuf + 1, psEnc->sCmn.frame_length );
130 
131     /*******************************************/
132     /* Copy new frame to front of input buffer */
133     /*******************************************/
134     silk_short2float_array( x_frame + LA_SHAPE_MS * psEnc->sCmn.fs_kHz, psEnc->sCmn.inputBuf + 1, psEnc->sCmn.frame_length );
135 
136     /* Add tiny signal to avoid high CPU load from denormalized floating point numbers */
137     for( i = 0; i < 8; i++ ) {
138         x_frame[ LA_SHAPE_MS * psEnc->sCmn.fs_kHz + i * ( psEnc->sCmn.frame_length >> 3 ) ] += ( 1 - ( i & 2 ) ) * 1e-6f;
139     }
140 
141     if( !psEnc->sCmn.prefillFlag ) {
142         /*****************************************/
143         /* Find pitch lags, initial LPC analysis */
144         /*****************************************/
145         silk_find_pitch_lags_FLP( psEnc, &sEncCtrl, res_pitch, x_frame, psEnc->sCmn.arch );
146 
147         /************************/
148         /* Noise shape analysis */
149         /************************/
150         silk_noise_shape_analysis_FLP( psEnc, &sEncCtrl, res_pitch_frame, x_frame );
151 
152         /***************************************************/
153         /* Find linear prediction coefficients (LPC + LTP) */
154         /***************************************************/
155         silk_find_pred_coefs_FLP( psEnc, &sEncCtrl, res_pitch_frame, x_frame, condCoding );
156 
157         /****************************************/
158         /* Process gains                        */
159         /****************************************/
160         silk_process_gains_FLP( psEnc, &sEncCtrl, condCoding );
161 
162         /****************************************/
163         /* Low Bitrate Redundant Encoding       */
164         /****************************************/
165         silk_LBRR_encode_FLP( psEnc, &sEncCtrl, x_frame, condCoding );
166 
167         /* Loop over quantizer and entroy coding to control bitrate */
168         maxIter = 6;
169         gainMult_Q8 = SILK_FIX_CONST( 1, 8 );
170         found_lower = 0;
171         found_upper = 0;
172         gainsID = silk_gains_ID( psEnc->sCmn.indices.GainsIndices, psEnc->sCmn.nb_subfr );
173         gainsID_lower = -1;
174         gainsID_upper = -1;
175         /* Copy part of the input state */
176         silk_memcpy( &sRangeEnc_copy, psRangeEnc, sizeof( ec_enc ) );
177         silk_memcpy( &sNSQ_copy, &psEnc->sCmn.sNSQ, sizeof( silk_nsq_state ) );
178         seed_copy = psEnc->sCmn.indices.Seed;
179         ec_prevLagIndex_copy = psEnc->sCmn.ec_prevLagIndex;
180         ec_prevSignalType_copy = psEnc->sCmn.ec_prevSignalType;
181         for( iter = 0; ; iter++ ) {
182             if( gainsID == gainsID_lower ) {
183                 nBits = nBits_lower;
184             } else if( gainsID == gainsID_upper ) {
185                 nBits = nBits_upper;
186             } else {
187                 /* Restore part of the input state */
188                 if( iter > 0 ) {
189                     silk_memcpy( psRangeEnc, &sRangeEnc_copy, sizeof( ec_enc ) );
190                     silk_memcpy( &psEnc->sCmn.sNSQ, &sNSQ_copy, sizeof( silk_nsq_state ) );
191                     psEnc->sCmn.indices.Seed = seed_copy;
192                     psEnc->sCmn.ec_prevLagIndex = ec_prevLagIndex_copy;
193                     psEnc->sCmn.ec_prevSignalType = ec_prevSignalType_copy;
194                 }
195 
196                 /*****************************************/
197                 /* Noise shaping quantization            */
198                 /*****************************************/
199                 silk_NSQ_wrapper_FLP( psEnc, &sEncCtrl, &psEnc->sCmn.indices, &psEnc->sCmn.sNSQ, psEnc->sCmn.pulses, x_frame );
200 
201                 if ( iter == maxIter && !found_lower ) {
202                     silk_memcpy( &sRangeEnc_copy2, psRangeEnc, sizeof( ec_enc ) );
203                 }
204 
205                 /****************************************/
206                 /* Encode Parameters                    */
207                 /****************************************/
208                 silk_encode_indices( &psEnc->sCmn, psRangeEnc, psEnc->sCmn.nFramesEncoded, 0, condCoding );
209 
210                 /****************************************/
211                 /* Encode Excitation Signal             */
212                 /****************************************/
213                 silk_encode_pulses( psRangeEnc, psEnc->sCmn.indices.signalType, psEnc->sCmn.indices.quantOffsetType,
214                       psEnc->sCmn.pulses, psEnc->sCmn.frame_length );
215 
216                 nBits = ec_tell( psRangeEnc );
217 
218                 /* If we still bust after the last iteration, do some damage control. */
219                 if ( iter == maxIter && !found_lower && nBits > maxBits ) {
220                     silk_memcpy( psRangeEnc, &sRangeEnc_copy2, sizeof( ec_enc ) );
221 
222                     /* Keep gains the same as the last frame. */
223                     psEnc->sShape.LastGainIndex = sEncCtrl.lastGainIndexPrev;
224                     for ( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) {
225                         psEnc->sCmn.indices.GainsIndices[ i ] = 4;
226                     }
227                     if (condCoding != CODE_CONDITIONALLY) {
228                        psEnc->sCmn.indices.GainsIndices[ 0 ] = sEncCtrl.lastGainIndexPrev;
229                     }
230                     psEnc->sCmn.ec_prevLagIndex = ec_prevLagIndex_copy;
231                     psEnc->sCmn.ec_prevSignalType = ec_prevSignalType_copy;
232                     /* Clear all pulses. */
233                     for ( i = 0; i < psEnc->sCmn.frame_length; i++ ) {
234                         psEnc->sCmn.pulses[ i ] = 0;
235                     }
236 
237                     silk_encode_indices( &psEnc->sCmn, psRangeEnc, psEnc->sCmn.nFramesEncoded, 0, condCoding );
238 
239                     silk_encode_pulses( psRangeEnc, psEnc->sCmn.indices.signalType, psEnc->sCmn.indices.quantOffsetType,
240                         psEnc->sCmn.pulses, psEnc->sCmn.frame_length );
241 
242                     nBits = ec_tell( psRangeEnc );
243                 }
244 
245                 if( useCBR == 0 && iter == 0 && nBits <= maxBits ) {
246                     break;
247                 }
248             }
249 
250             if( iter == maxIter ) {
251                 if( found_lower && ( gainsID == gainsID_lower || nBits > maxBits ) ) {
252                     /* Restore output state from earlier iteration that did meet the bitrate budget */
253                     silk_memcpy( psRangeEnc, &sRangeEnc_copy2, sizeof( ec_enc ) );
254                     celt_assert( sRangeEnc_copy2.offs <= 1275 );
255                     silk_memcpy( psRangeEnc->buf, ec_buf_copy, sRangeEnc_copy2.offs );
256                     silk_memcpy( &psEnc->sCmn.sNSQ, &sNSQ_copy2, sizeof( silk_nsq_state ) );
257                     psEnc->sShape.LastGainIndex = LastGainIndex_copy2;
258                 }
259                 break;
260             }
261 
262             if( nBits > maxBits ) {
263                 if( found_lower == 0 && iter >= 2 ) {
264                     /* Adjust the quantizer's rate/distortion tradeoff and discard previous "upper" results */
265                     sEncCtrl.Lambda = silk_max_float(sEncCtrl.Lambda*1.5f, 1.5f);
266                     /* Reducing dithering can help us hit the target. */
267                     psEnc->sCmn.indices.quantOffsetType = 0;
268                     found_upper = 0;
269                     gainsID_upper = -1;
270                 } else {
271                     found_upper = 1;
272                     nBits_upper = nBits;
273                     gainMult_upper = gainMult_Q8;
274                     gainsID_upper = gainsID;
275                 }
276             } else if( nBits < maxBits - bits_margin ) {
277                 found_lower = 1;
278                 nBits_lower = nBits;
279                 gainMult_lower = gainMult_Q8;
280                 if( gainsID != gainsID_lower ) {
281                     gainsID_lower = gainsID;
282                     /* Copy part of the output state */
283                     silk_memcpy( &sRangeEnc_copy2, psRangeEnc, sizeof( ec_enc ) );
284                     celt_assert( psRangeEnc->offs <= 1275 );
285                     silk_memcpy( ec_buf_copy, psRangeEnc->buf, psRangeEnc->offs );
286                     silk_memcpy( &sNSQ_copy2, &psEnc->sCmn.sNSQ, sizeof( silk_nsq_state ) );
287                     LastGainIndex_copy2 = psEnc->sShape.LastGainIndex;
288                 }
289             } else {
290                 /* Close enough */
291                 break;
292             }
293 
294             if ( !found_lower && nBits > maxBits ) {
295                 int j;
296                 for ( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) {
297                     int sum=0;
298                     for ( j = i*psEnc->sCmn.subfr_length; j < (i+1)*psEnc->sCmn.subfr_length; j++ ) {
299                         sum += abs( psEnc->sCmn.pulses[j] );
300                     }
301                     if ( iter == 0 || (sum < best_sum[i] && !gain_lock[i]) ) {
302                         best_sum[i] = sum;
303                         best_gain_mult[i] = gainMult_Q8;
304                     } else {
305                         gain_lock[i] = 1;
306                     }
307                 }
308             }
309             if( ( found_lower & found_upper ) == 0 ) {
310                 /* Adjust gain according to high-rate rate/distortion curve */
311                 if( nBits > maxBits ) {
312                     gainMult_Q8 = silk_min_32( 1024, gainMult_Q8*3/2 );
313                 } else {
314                     gainMult_Q8 = silk_max_32( 64, gainMult_Q8*4/5 );
315                 }
316             } else {
317                 /* Adjust gain by interpolating */
318                 gainMult_Q8 = gainMult_lower + ( ( gainMult_upper - gainMult_lower ) * ( maxBits - nBits_lower ) ) / ( nBits_upper - nBits_lower );
319                 /* New gain multplier must be between 25% and 75% of old range (note that gainMult_upper < gainMult_lower) */
320                 if( gainMult_Q8 > silk_ADD_RSHIFT32( gainMult_lower, gainMult_upper - gainMult_lower, 2 ) ) {
321                     gainMult_Q8 = silk_ADD_RSHIFT32( gainMult_lower, gainMult_upper - gainMult_lower, 2 );
322                 } else
323                 if( gainMult_Q8 < silk_SUB_RSHIFT32( gainMult_upper, gainMult_upper - gainMult_lower, 2 ) ) {
324                     gainMult_Q8 = silk_SUB_RSHIFT32( gainMult_upper, gainMult_upper - gainMult_lower, 2 );
325                 }
326             }
327 
328             for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) {
329                 opus_int16 tmp;
330                 if ( gain_lock[i] ) {
331                     tmp = best_gain_mult[i];
332                 } else {
333                     tmp = gainMult_Q8;
334                 }
335                 pGains_Q16[ i ] = silk_LSHIFT_SAT32( silk_SMULWB( sEncCtrl.GainsUnq_Q16[ i ], tmp ), 8 );
336             }
337 
338             /* Quantize gains */
339             psEnc->sShape.LastGainIndex = sEncCtrl.lastGainIndexPrev;
340             silk_gains_quant( psEnc->sCmn.indices.GainsIndices, pGains_Q16,
341                   &psEnc->sShape.LastGainIndex, condCoding == CODE_CONDITIONALLY, psEnc->sCmn.nb_subfr );
342 
343             /* Unique identifier of gains vector */
344             gainsID = silk_gains_ID( psEnc->sCmn.indices.GainsIndices, psEnc->sCmn.nb_subfr );
345 
346             /* Overwrite unquantized gains with quantized gains and convert back to Q0 from Q16 */
347             for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) {
348                 sEncCtrl.Gains[ i ] = pGains_Q16[ i ] / 65536.0f;
349             }
350         }
351     }
352 
353     /* Update input buffer */
354     silk_memmove( psEnc->x_buf, &psEnc->x_buf[ psEnc->sCmn.frame_length ],
355         ( psEnc->sCmn.ltp_mem_length + LA_SHAPE_MS * psEnc->sCmn.fs_kHz ) * sizeof( silk_float ) );
356 
357     /* Exit without entropy coding */
358     if( psEnc->sCmn.prefillFlag ) {
359         /* No payload */
360         *pnBytesOut = 0;
361         return ret;
362     }
363 
364     /* Parameters needed for next frame */
365     psEnc->sCmn.prevLag        = sEncCtrl.pitchL[ psEnc->sCmn.nb_subfr - 1 ];
366     psEnc->sCmn.prevSignalType = psEnc->sCmn.indices.signalType;
367 
368     /****************************************/
369     /* Finalize payload                     */
370     /****************************************/
371     psEnc->sCmn.first_frame_after_reset = 0;
372     /* Payload size */
373     *pnBytesOut = silk_RSHIFT( ec_tell( psRangeEnc ) + 7, 3 );
374 
375     return ret;
376 }
377 
378 /* Low-Bitrate Redundancy (LBRR) encoding. Reuse all parameters but encode excitation at lower bitrate  */
silk_LBRR_encode_FLP(silk_encoder_state_FLP * psEnc,silk_encoder_control_FLP * psEncCtrl,const silk_float xfw[],opus_int condCoding)379 static OPUS_INLINE void silk_LBRR_encode_FLP(
380     silk_encoder_state_FLP          *psEnc,                             /* I/O  Encoder state FLP                           */
381     silk_encoder_control_FLP        *psEncCtrl,                         /* I/O  Encoder control FLP                         */
382     const silk_float                xfw[],                              /* I    Input signal                                */
383     opus_int                        condCoding                          /* I    The type of conditional coding used so far for this frame */
384 )
385 {
386     opus_int     k;
387     opus_int32   Gains_Q16[ MAX_NB_SUBFR ];
388     silk_float   TempGains[ MAX_NB_SUBFR ];
389     SideInfoIndices *psIndices_LBRR = &psEnc->sCmn.indices_LBRR[ psEnc->sCmn.nFramesEncoded ];
390     silk_nsq_state sNSQ_LBRR;
391 
392     /*******************************************/
393     /* Control use of inband LBRR              */
394     /*******************************************/
395     if( psEnc->sCmn.LBRR_enabled && psEnc->sCmn.speech_activity_Q8 > SILK_FIX_CONST( LBRR_SPEECH_ACTIVITY_THRES, 8 ) ) {
396         psEnc->sCmn.LBRR_flags[ psEnc->sCmn.nFramesEncoded ] = 1;
397 
398         /* Copy noise shaping quantizer state and quantization indices from regular encoding */
399         silk_memcpy( &sNSQ_LBRR, &psEnc->sCmn.sNSQ, sizeof( silk_nsq_state ) );
400         silk_memcpy( psIndices_LBRR, &psEnc->sCmn.indices, sizeof( SideInfoIndices ) );
401 
402         /* Save original gains */
403         silk_memcpy( TempGains, psEncCtrl->Gains, psEnc->sCmn.nb_subfr * sizeof( silk_float ) );
404 
405         if( psEnc->sCmn.nFramesEncoded == 0 || psEnc->sCmn.LBRR_flags[ psEnc->sCmn.nFramesEncoded - 1 ] == 0 ) {
406             /* First frame in packet or previous frame not LBRR coded */
407             psEnc->sCmn.LBRRprevLastGainIndex = psEnc->sShape.LastGainIndex;
408 
409             /* Increase Gains to get target LBRR rate */
410             psIndices_LBRR->GainsIndices[ 0 ] += psEnc->sCmn.LBRR_GainIncreases;
411             psIndices_LBRR->GainsIndices[ 0 ] = silk_min_int( psIndices_LBRR->GainsIndices[ 0 ], N_LEVELS_QGAIN - 1 );
412         }
413 
414         /* Decode to get gains in sync with decoder */
415         silk_gains_dequant( Gains_Q16, psIndices_LBRR->GainsIndices,
416             &psEnc->sCmn.LBRRprevLastGainIndex, condCoding == CODE_CONDITIONALLY, psEnc->sCmn.nb_subfr );
417 
418         /* Overwrite unquantized gains with quantized gains and convert back to Q0 from Q16 */
419         for( k = 0; k <  psEnc->sCmn.nb_subfr; k++ ) {
420             psEncCtrl->Gains[ k ] = Gains_Q16[ k ] * ( 1.0f / 65536.0f );
421         }
422 
423         /*****************************************/
424         /* Noise shaping quantization            */
425         /*****************************************/
426         silk_NSQ_wrapper_FLP( psEnc, psEncCtrl, psIndices_LBRR, &sNSQ_LBRR,
427             psEnc->sCmn.pulses_LBRR[ psEnc->sCmn.nFramesEncoded ], xfw );
428 
429         /* Restore original gains */
430         silk_memcpy( psEncCtrl->Gains, TempGains, psEnc->sCmn.nb_subfr * sizeof( silk_float ) );
431     }
432 }
433