xref: /aosp_15_r20/external/libopus/silk/gain_quant.c (revision a58d3d2adb790c104798cd88c8a3aff4fa8b82cc)
1*a58d3d2aSXin Li /***********************************************************************
2*a58d3d2aSXin Li Copyright (c) 2006-2011, Skype Limited. All rights reserved.
3*a58d3d2aSXin Li Redistribution and use in source and binary forms, with or without
4*a58d3d2aSXin Li modification, are permitted provided that the following conditions
5*a58d3d2aSXin Li are met:
6*a58d3d2aSXin Li - Redistributions of source code must retain the above copyright notice,
7*a58d3d2aSXin Li this list of conditions and the following disclaimer.
8*a58d3d2aSXin Li - Redistributions in binary form must reproduce the above copyright
9*a58d3d2aSXin Li notice, this list of conditions and the following disclaimer in the
10*a58d3d2aSXin Li documentation and/or other materials provided with the distribution.
11*a58d3d2aSXin Li - Neither the name of Internet Society, IETF or IETF Trust, nor the
12*a58d3d2aSXin Li names of specific contributors, may be used to endorse or promote
13*a58d3d2aSXin Li products derived from this software without specific prior written
14*a58d3d2aSXin Li permission.
15*a58d3d2aSXin Li THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16*a58d3d2aSXin Li AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17*a58d3d2aSXin Li IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18*a58d3d2aSXin Li ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
19*a58d3d2aSXin Li LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20*a58d3d2aSXin Li CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21*a58d3d2aSXin Li SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22*a58d3d2aSXin Li INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23*a58d3d2aSXin Li CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24*a58d3d2aSXin Li ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25*a58d3d2aSXin Li POSSIBILITY OF SUCH DAMAGE.
26*a58d3d2aSXin Li ***********************************************************************/
27*a58d3d2aSXin Li 
28*a58d3d2aSXin Li #ifdef HAVE_CONFIG_H
29*a58d3d2aSXin Li #include "config.h"
30*a58d3d2aSXin Li #endif
31*a58d3d2aSXin Li 
32*a58d3d2aSXin Li #include "main.h"
33*a58d3d2aSXin Li 
34*a58d3d2aSXin Li #define OFFSET                  ( ( MIN_QGAIN_DB * 128 ) / 6 + 16 * 128 )
35*a58d3d2aSXin Li #define SCALE_Q16               ( ( 65536 * ( N_LEVELS_QGAIN - 1 ) ) / ( ( ( MAX_QGAIN_DB - MIN_QGAIN_DB ) * 128 ) / 6 ) )
36*a58d3d2aSXin Li #define INV_SCALE_Q16           ( ( 65536 * ( ( ( MAX_QGAIN_DB - MIN_QGAIN_DB ) * 128 ) / 6 ) ) / ( N_LEVELS_QGAIN - 1 ) )
37*a58d3d2aSXin Li 
38*a58d3d2aSXin Li /* Gain scalar quantization with hysteresis, uniform on log scale */
silk_gains_quant(opus_int8 ind[MAX_NB_SUBFR],opus_int32 gain_Q16[MAX_NB_SUBFR],opus_int8 * prev_ind,const opus_int conditional,const opus_int nb_subfr)39*a58d3d2aSXin Li void silk_gains_quant(
40*a58d3d2aSXin Li     opus_int8                   ind[ MAX_NB_SUBFR ],            /* O    gain indices                                */
41*a58d3d2aSXin Li     opus_int32                  gain_Q16[ MAX_NB_SUBFR ],       /* I/O  gains (quantized out)                       */
42*a58d3d2aSXin Li     opus_int8                   *prev_ind,                      /* I/O  last index in previous frame                */
43*a58d3d2aSXin Li     const opus_int              conditional,                    /* I    first gain is delta coded if 1              */
44*a58d3d2aSXin Li     const opus_int              nb_subfr                        /* I    number of subframes                         */
45*a58d3d2aSXin Li )
46*a58d3d2aSXin Li {
47*a58d3d2aSXin Li     opus_int k, double_step_size_threshold;
48*a58d3d2aSXin Li 
49*a58d3d2aSXin Li     for( k = 0; k < nb_subfr; k++ ) {
50*a58d3d2aSXin Li         /* Convert to log scale, scale, floor() */
51*a58d3d2aSXin Li         ind[ k ] = silk_SMULWB( SCALE_Q16, silk_lin2log( gain_Q16[ k ] ) - OFFSET );
52*a58d3d2aSXin Li 
53*a58d3d2aSXin Li         /* Round towards previous quantized gain (hysteresis) */
54*a58d3d2aSXin Li         if( ind[ k ] < *prev_ind ) {
55*a58d3d2aSXin Li             ind[ k ]++;
56*a58d3d2aSXin Li         }
57*a58d3d2aSXin Li         ind[ k ] = silk_LIMIT_int( ind[ k ], 0, N_LEVELS_QGAIN - 1 );
58*a58d3d2aSXin Li 
59*a58d3d2aSXin Li         /* Compute delta indices and limit */
60*a58d3d2aSXin Li         if( k == 0 && conditional == 0 ) {
61*a58d3d2aSXin Li             /* Full index */
62*a58d3d2aSXin Li             ind[ k ] = silk_LIMIT_int( ind[ k ], *prev_ind + MIN_DELTA_GAIN_QUANT, N_LEVELS_QGAIN - 1 );
63*a58d3d2aSXin Li             *prev_ind = ind[ k ];
64*a58d3d2aSXin Li         } else {
65*a58d3d2aSXin Li             /* Delta index */
66*a58d3d2aSXin Li             ind[ k ] = ind[ k ] - *prev_ind;
67*a58d3d2aSXin Li 
68*a58d3d2aSXin Li             /* Double the quantization step size for large gain increases, so that the max gain level can be reached */
69*a58d3d2aSXin Li             double_step_size_threshold = 2 * MAX_DELTA_GAIN_QUANT - N_LEVELS_QGAIN + *prev_ind;
70*a58d3d2aSXin Li             if( ind[ k ] > double_step_size_threshold ) {
71*a58d3d2aSXin Li                 ind[ k ] = double_step_size_threshold + silk_RSHIFT( ind[ k ] - double_step_size_threshold + 1, 1 );
72*a58d3d2aSXin Li             }
73*a58d3d2aSXin Li 
74*a58d3d2aSXin Li             ind[ k ] = silk_LIMIT_int( ind[ k ], MIN_DELTA_GAIN_QUANT, MAX_DELTA_GAIN_QUANT );
75*a58d3d2aSXin Li 
76*a58d3d2aSXin Li             /* Accumulate deltas */
77*a58d3d2aSXin Li             if( ind[ k ] > double_step_size_threshold ) {
78*a58d3d2aSXin Li                 *prev_ind += silk_LSHIFT( ind[ k ], 1 ) - double_step_size_threshold;
79*a58d3d2aSXin Li                 *prev_ind = silk_min_int( *prev_ind, N_LEVELS_QGAIN - 1 );
80*a58d3d2aSXin Li             } else {
81*a58d3d2aSXin Li                 *prev_ind += ind[ k ];
82*a58d3d2aSXin Li             }
83*a58d3d2aSXin Li 
84*a58d3d2aSXin Li             /* Shift to make non-negative */
85*a58d3d2aSXin Li             ind[ k ] -= MIN_DELTA_GAIN_QUANT;
86*a58d3d2aSXin Li         }
87*a58d3d2aSXin Li 
88*a58d3d2aSXin Li         /* Scale and convert to linear scale */
89*a58d3d2aSXin Li         gain_Q16[ k ] = silk_log2lin( silk_min_32( silk_SMULWB( INV_SCALE_Q16, *prev_ind ) + OFFSET, 3967 ) ); /* 3967 = 31 in Q7 */
90*a58d3d2aSXin Li     }
91*a58d3d2aSXin Li }
92*a58d3d2aSXin Li 
93*a58d3d2aSXin Li /* Gains scalar dequantization, uniform on log scale */
silk_gains_dequant(opus_int32 gain_Q16[MAX_NB_SUBFR],const opus_int8 ind[MAX_NB_SUBFR],opus_int8 * prev_ind,const opus_int conditional,const opus_int nb_subfr)94*a58d3d2aSXin Li void silk_gains_dequant(
95*a58d3d2aSXin Li     opus_int32                  gain_Q16[ MAX_NB_SUBFR ],       /* O    quantized gains                             */
96*a58d3d2aSXin Li     const opus_int8             ind[ MAX_NB_SUBFR ],            /* I    gain indices                                */
97*a58d3d2aSXin Li     opus_int8                   *prev_ind,                      /* I/O  last index in previous frame                */
98*a58d3d2aSXin Li     const opus_int              conditional,                    /* I    first gain is delta coded if 1              */
99*a58d3d2aSXin Li     const opus_int              nb_subfr                        /* I    number of subframes                          */
100*a58d3d2aSXin Li )
101*a58d3d2aSXin Li {
102*a58d3d2aSXin Li     opus_int   k, ind_tmp, double_step_size_threshold;
103*a58d3d2aSXin Li 
104*a58d3d2aSXin Li     for( k = 0; k < nb_subfr; k++ ) {
105*a58d3d2aSXin Li         if( k == 0 && conditional == 0 ) {
106*a58d3d2aSXin Li             /* Gain index is not allowed to go down more than 16 steps (~21.8 dB) */
107*a58d3d2aSXin Li             *prev_ind = silk_max_int( ind[ k ], *prev_ind - 16 );
108*a58d3d2aSXin Li         } else {
109*a58d3d2aSXin Li             /* Delta index */
110*a58d3d2aSXin Li             ind_tmp = ind[ k ] + MIN_DELTA_GAIN_QUANT;
111*a58d3d2aSXin Li 
112*a58d3d2aSXin Li             /* Accumulate deltas */
113*a58d3d2aSXin Li             double_step_size_threshold = 2 * MAX_DELTA_GAIN_QUANT - N_LEVELS_QGAIN + *prev_ind;
114*a58d3d2aSXin Li             if( ind_tmp > double_step_size_threshold ) {
115*a58d3d2aSXin Li                 *prev_ind += silk_LSHIFT( ind_tmp, 1 ) - double_step_size_threshold;
116*a58d3d2aSXin Li             } else {
117*a58d3d2aSXin Li                 *prev_ind += ind_tmp;
118*a58d3d2aSXin Li             }
119*a58d3d2aSXin Li         }
120*a58d3d2aSXin Li         *prev_ind = silk_LIMIT_int( *prev_ind, 0, N_LEVELS_QGAIN - 1 );
121*a58d3d2aSXin Li 
122*a58d3d2aSXin Li         /* Scale and convert to linear scale */
123*a58d3d2aSXin Li         gain_Q16[ k ] = silk_log2lin( silk_min_32( silk_SMULWB( INV_SCALE_Q16, *prev_ind ) + OFFSET, 3967 ) ); /* 3967 = 31 in Q7 */
124*a58d3d2aSXin Li     }
125*a58d3d2aSXin Li }
126*a58d3d2aSXin Li 
127*a58d3d2aSXin Li /* Compute unique identifier of gain indices vector */
silk_gains_ID(const opus_int8 ind[MAX_NB_SUBFR],const opus_int nb_subfr)128*a58d3d2aSXin Li opus_int32 silk_gains_ID(                                       /* O    returns unique identifier of gains          */
129*a58d3d2aSXin Li     const opus_int8             ind[ MAX_NB_SUBFR ],            /* I    gain indices                                */
130*a58d3d2aSXin Li     const opus_int              nb_subfr                        /* I    number of subframes                         */
131*a58d3d2aSXin Li )
132*a58d3d2aSXin Li {
133*a58d3d2aSXin Li     opus_int   k;
134*a58d3d2aSXin Li     opus_int32 gainsID;
135*a58d3d2aSXin Li 
136*a58d3d2aSXin Li     gainsID = 0;
137*a58d3d2aSXin Li     for( k = 0; k < nb_subfr; k++ ) {
138*a58d3d2aSXin Li         gainsID = silk_ADD_LSHIFT32( ind[ k ], gainsID, 8 );
139*a58d3d2aSXin Li     }
140*a58d3d2aSXin Li 
141*a58d3d2aSXin Li     return gainsID;
142*a58d3d2aSXin Li }
143