static void ra144_encode_subblock(RA144Context *ractx,

                                  const int16_t *sblock_data,

                                  const int16_t *lpc_coefs, unsigned int rms,

                                  PutBitContext *pb)

{

    float data[BLOCKSIZE] = { 0 }, work[LPC_ORDER + BLOCKSIZE];

    float coefs[LPC_ORDER];

    float zero[BLOCKSIZE], cba[BLOCKSIZE], cb1[BLOCKSIZE], cb2[BLOCKSIZE];

    int16_t cba_vect[BLOCKSIZE];

    int cba_idx, cb1_idx, cb2_idx, gain;

    int i, n;

    unsigned m[3];

    float g[3];

    float error, best_error;



    for (i = 0; i < LPC_ORDER; i++) {

        work[i] = ractx->curr_sblock[BLOCKSIZE + i];

        coefs[i] = lpc_coefs[i] * (1/4096.0);

    }



    /**

     * Calculate the zero-input response of the LPC filter and subtract it from

     * input data.

     */

    ff_celp_lp_synthesis_filterf(work + LPC_ORDER, coefs, data, BLOCKSIZE,

                                 LPC_ORDER);

    for (i = 0; i < BLOCKSIZE; i++) {

        zero[i] = work[LPC_ORDER + i];

        data[i] = sblock_data[i] - zero[i];

    }



    /**

     * Codebook search is performed without taking into account the contribution

     * of the previous subblock, since it has been just subtracted from input

     * data.

     */

    memset(work, 0, LPC_ORDER * sizeof(*work));



    cba_idx = adaptive_cb_search(ractx->adapt_cb, work + LPC_ORDER, coefs,

                                 data);

    if (cba_idx) {

        /**

         * The filtered vector from the adaptive codebook can be retrieved from

         * work, see implementation of adaptive_cb_search().

         */

        memcpy(cba, work + LPC_ORDER, sizeof(cba));



        ff_copy_and_dup(cba_vect, ractx->adapt_cb, cba_idx + BLOCKSIZE / 2 - 1);

        m[0] = (ff_irms(cba_vect) * rms) >> 12;

    }

    fixed_cb_search(work + LPC_ORDER, coefs, data, cba_idx, &cb1_idx, &cb2_idx);

    for (i = 0; i < BLOCKSIZE; i++) {

        cb1[i] = ff_cb1_vects[cb1_idx][i];

        cb2[i] = ff_cb2_vects[cb2_idx][i];

    }

    ff_celp_lp_synthesis_filterf(work + LPC_ORDER, coefs, cb1, BLOCKSIZE,

                                 LPC_ORDER);

    memcpy(cb1, work + LPC_ORDER, sizeof(cb1));

    m[1] = (ff_cb1_base[cb1_idx] * rms) >> 8;

    ff_celp_lp_synthesis_filterf(work + LPC_ORDER, coefs, cb2, BLOCKSIZE,

                                 LPC_ORDER);

    memcpy(cb2, work + LPC_ORDER, sizeof(cb2));

    m[2] = (ff_cb2_base[cb2_idx] * rms) >> 8;

    best_error = FLT_MAX;

    gain = 0;

    for (n = 0; n < 256; n++) {

        g[1] = ((ff_gain_val_tab[n][1] * m[1]) >> ff_gain_exp_tab[n]) *

               (1/4096.0);

        g[2] = ((ff_gain_val_tab[n][2] * m[2]) >> ff_gain_exp_tab[n]) *

               (1/4096.0);

        error = 0;

        if (cba_idx) {

            g[0] = ((ff_gain_val_tab[n][0] * m[0]) >> ff_gain_exp_tab[n]) *

                   (1/4096.0);

            for (i = 0; i < BLOCKSIZE; i++) {

                data[i] = zero[i] + g[0] * cba[i] + g[1] * cb1[i] +

                          g[2] * cb2[i];

                error += (data[i] - sblock_data[i]) *

                         (data[i] - sblock_data[i]);

            }

        } else {

            for (i = 0; i < BLOCKSIZE; i++) {

                data[i] = zero[i] + g[1] * cb1[i] + g[2] * cb2[i];

                error += (data[i] - sblock_data[i]) *

                         (data[i] - sblock_data[i]);

            }

        }

        if (error < best_error) {

            best_error = error;

            gain = n;

        }

    }

    put_bits(pb, 7, cba_idx);

    put_bits(pb, 8, gain);

    put_bits(pb, 7, cb1_idx);

    put_bits(pb, 7, cb2_idx);

    ff_subblock_synthesis(ractx, lpc_coefs, cba_idx, cb1_idx, cb2_idx, rms,

                          gain);

}
